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:
parent
9ed1890de8
commit
d4cf1ad3a1
11 changed files with 320 additions and 11 deletions
|
|
@ -131,7 +131,16 @@ export interface ShotFrame { src: string; x?: number; dy?: number; scale?: numbe
|
|||
/** bg: gradient stops (2-3 colours), one colour (flat) or a CSS gradient string. image: a photo background (path
|
||||
* relative to the config, cropped to cover) under a dark overlay (0-0.9, default 0.45) that keeps white ink legible. */
|
||||
export interface Palette { bg: string | [string, string] | [string, string, string]; glow: string; ink: string; shadow: string; image?: string; overlay?: number }
|
||||
export interface ShotScene { id: string; palette: string | Palette; hero?: boolean; frames: ShotFrame[]; badges?: ShotBadgeSlot[]; over?: number }
|
||||
export interface ShotScene { id: string; palette: string | Palette; hero?: boolean; frames: ShotFrame[]; badges?: ShotBadgeSlot[]; over?: number
|
||||
/** layout "bleed": the corner the caption sits in (top / bottom, left / right). Default "tl". */
|
||||
corner?: 'tl' | 'tr' | 'bl' | 'br';
|
||||
/** layout "bleed": caption size multiplier (0.6-1.4, default 1). */
|
||||
captionScale?: number;
|
||||
/** layout "bleed": the caption's maximum width as a share of the image width (0.2-0.9; default 0.4 landscape,
|
||||
* 0.84 portrait). Lines that do not fit shrink, down to 60 %. */
|
||||
captionWidth?: number;
|
||||
/** layout "bleed": the caption's distance from its corner as a share of the short side (0.01-0.15, default 0.05). */
|
||||
captionInset?: number }
|
||||
|
||||
/** A local font file for shots.fonts. license: 'OFL-1.1', 'proprietary' or a short note (shown by `shots fonts`;
|
||||
* `shots check` warns without one). weight / style: the @font-face descriptors (default: all weights, normal). */
|
||||
|
|
@ -144,6 +153,16 @@ export interface ShotsConfig {
|
|||
* device frame, headline + subline, no sparkles or badges). Default: app for the app / subscription-app profiles,
|
||||
* else game. */
|
||||
style?: 'game' | 'app';
|
||||
/** "device" (default): the frames inside device outlines on the style's background, titles above. "bleed": the
|
||||
* frame fills the whole image (no device, no background) and the scene's title is a short caption in one corner
|
||||
* (scene.corner), legible through a text shadow and a soft glow only. Bleed frames are captured per size at the
|
||||
* size's own pixels: <frames>/<languageId>/<size>/<name>.png (feature: <frames>/<languageId>/feature/<name>);
|
||||
* that includes the mac and chromebook sizes. */
|
||||
layout?: 'device' | 'bleed';
|
||||
/** "landscape" (only with layout "bleed"): every portrait screenshot size is rendered landscape (width and height
|
||||
* swapped; the feature graphic, mac and chromebook are landscape anyway). Both stores accept landscape
|
||||
* screenshots. Default "portrait". */
|
||||
orientation?: 'portrait' | 'landscape';
|
||||
/** JSON file: { [languageId]: { [sceneId]: { eyebrow, title: [line1, line2], sub, badges: [[big, small?]] } } } */
|
||||
copy: string;
|
||||
/** Raw frames: <frames>/<languageId>/<phone|tablet>/<name>.png */
|
||||
|
|
@ -164,6 +183,8 @@ export interface ShotsConfig {
|
|||
* bottom edge on purpose (shots check then allows it). `scale` (0.5-1.5, default 1) multiplies the phone's width
|
||||
* (still clamped to the canvas with 'contain'). */
|
||||
feature?: { frame: string; palette?: string | Palette; fit?: 'contain' | 'bleed'; scale?: number;
|
||||
/** layout "bleed": the name on the feature graphic when there is no logo (default app.name). */
|
||||
title?: string;
|
||||
/** Photo background for the feature graphic (path relative to the config, or { image, overlay }); wins over the
|
||||
* palette's image. Also usable for the App Store Header and Search Results art. */
|
||||
background?: string | { image: string; overlay?: number } };
|
||||
|
|
@ -1214,6 +1235,15 @@ export function validateConfig(c: unknown): string[] {
|
|||
const s = cfg.shots;
|
||||
for (const k of ['copy', 'frames', 'out'] as const) if (!s[k]) e.push(`shots.${k}: missing`);
|
||||
if (s.style !== undefined && s.style !== 'game' && s.style !== 'app') e.push('shots.style: game | app');
|
||||
if (s.layout !== undefined && s.layout !== 'device' && s.layout !== 'bleed') e.push('shots.layout: device | bleed');
|
||||
if (s.orientation !== undefined && s.orientation !== 'portrait' && s.orientation !== 'landscape') e.push('shots.orientation: portrait | landscape');
|
||||
else if (s.orientation === 'landscape' && s.layout !== 'bleed') e.push("shots.orientation: 'landscape' needs shots.layout: 'bleed' (the device layouts draw portrait phones)");
|
||||
for (const sc of s.scenes ?? []) {
|
||||
if (sc.corner !== undefined && !['tl', 'tr', 'bl', 'br'].includes(sc.corner)) e.push(`shots.scenes ${sc.id}: corner tl | tr | bl | br`);
|
||||
if (sc.captionScale !== undefined && !(sc.captionScale >= 0.6 && sc.captionScale <= 1.4)) e.push(`shots.scenes ${sc.id}: captionScale 0.6-1.4`);
|
||||
if (sc.captionWidth !== undefined && !(sc.captionWidth >= 0.2 && sc.captionWidth <= 0.9)) e.push(`shots.scenes ${sc.id}: captionWidth 0.2-0.9`);
|
||||
if (sc.captionInset !== undefined && !(sc.captionInset >= 0.01 && sc.captionInset <= 0.15)) e.push(`shots.scenes ${sc.id}: captionInset 0.01-0.15`);
|
||||
}
|
||||
if (!s.scenes?.length) e.push('shots.scenes: at least one scene');
|
||||
if (s.landscape?.frame !== undefined && s.landscape.frame !== 'window' && s.landscape.frame !== 'none') e.push("shots.landscape.frame: 'window' | 'none'");
|
||||
if (s.landscape?.side !== undefined && s.landscape.side !== 'left' && s.landscape.side !== 'right') e.push("shots.landscape.side: 'left' | 'right'");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue