@appshoteditor/shot-dsl 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/package.json +1 -1
- package/src/compose.ts +7 -0
- package/src/layout-system.ts +31 -10
package/README.md
CHANGED
|
@@ -64,7 +64,9 @@ validateTemplate(template); // { valid: true, errors: [] }
|
|
|
64
64
|
bleeds decisively: it grows toward the 90%-of-W cap, then shifts down. It clears with the
|
|
65
65
|
margin only when every ≥ 12% bleed would crop its focus band.
|
|
66
66
|
- `none`: always fully visible.
|
|
67
|
-
- `deep`: bleed
|
|
67
|
+
- `deep`: grows the subject toward a 25% bleed (still capped at 90% W). When growth alone can't
|
|
68
|
+
reach 25% (the size cap bites first), it shifts down too — but never further than a 12% bleed
|
|
69
|
+
needs, even though the target is 25%: it never shifts deeper just to force that target.
|
|
68
70
|
3. **No side tangents.** No subject is wider than 90% of W (`NO_TANGENT.maxWidth`). The part that is
|
|
69
71
|
actually on the canvas keeps ≥ 5% of W from both side edges. The only side bleed is a deliberate
|
|
70
72
|
panorama straddle across a seam.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appshoteditor/shot-dsl",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "App Shot Editor layout DSL + device-frame geometry — framework-free building blocks for composing editable App Store screenshot layouts. Intended for use via a bundler (Vite, esbuild, etc.).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/compose.ts
CHANGED
|
@@ -295,6 +295,12 @@ export interface ComposeScreenMetrics {
|
|
|
295
295
|
headlineSize: number;
|
|
296
296
|
/** Headline box top ÷ H (identical across a set by construction). */
|
|
297
297
|
headlineTop: number;
|
|
298
|
+
/**
|
|
299
|
+
* Bottom of the reserved text block (headline + subheadline + badge row) ÷ H. For `text-bottom`
|
|
300
|
+
* layouts the text block sits near the canvas bottom (not the top), so `top − textBottom` (the
|
|
301
|
+
* subject's top minus this) isn't a meaningful "gap under the text" for that layout.
|
|
302
|
+
*/
|
|
303
|
+
textBottom: number;
|
|
298
304
|
tilt: number;
|
|
299
305
|
/** Horizontal centre ÷ W (≠ 0.5 for a straddling panorama device). */
|
|
300
306
|
centerX: number;
|
|
@@ -2023,6 +2029,7 @@ export function composeSet(plan: ComposePlan): { template: Template; report: Com
|
|
|
2023
2029
|
tangent: inTangentZone(overshoot, p.boxHeight, H),
|
|
2024
2030
|
headlineSize: typo.headlineSize / W,
|
|
2025
2031
|
headlineTop: g.headlineTop / H,
|
|
2032
|
+
textBottom: (g.areaTop + typo.textArea) / H,
|
|
2026
2033
|
tilt: p.angle,
|
|
2027
2034
|
centerX: cx / W,
|
|
2028
2035
|
role: r.role,
|
package/src/layout-system.ts
CHANGED
|
@@ -17,7 +17,11 @@ export const NO_TANGENT = {
|
|
|
17
17
|
clearGap: 0.04,
|
|
18
18
|
/** A subject that bleeds must lose at least this × its own (rotated) height. */
|
|
19
19
|
minBleed: 0.12,
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* `bleed: "deep"` target, × the subject's height. Reached by growing the subject (up to
|
|
22
|
+
* `maxWidth`·W) — never by shifting it down past a decisive (`minBleed`) overshoot, since a
|
|
23
|
+
* further down-shift would just be empty space between the text and the subject.
|
|
24
|
+
*/
|
|
21
25
|
deepBleed: 0.25,
|
|
22
26
|
/** The focus band must end at least this × H inside the canvas edge. */
|
|
23
27
|
focusSafe: 0.02,
|
|
@@ -207,10 +211,15 @@ export interface VerticalResult {
|
|
|
207
211
|
* ≥ `clearGap`·H or bleeds by ≥ `minBleed` of the subject's height — never in between — and never
|
|
208
212
|
* pushes the focus band off-canvas. Options:
|
|
209
213
|
* - CLEAR: keep the near edge, shrink until the far edge clears with the margin.
|
|
210
|
-
* - BLEED: grow (up to
|
|
211
|
-
* the
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
+
* - BLEED: grow (up to its size cap) toward the target overshoot; only when growth alone can't get
|
|
215
|
+
* there (the size cap bites first) does the subject shift toward the far edge, and then only far
|
|
216
|
+
* enough for a decisive (`minBleed`) overshoot — never further just to reach a deeper target, which
|
|
217
|
+
* would otherwise leave empty space between the text and the subject. If the result hides the focus
|
|
218
|
+
* band, the placement instead targets the smallest decisive bleed (`minBleed`) that stays focus-safe
|
|
219
|
+
* — or near0 itself, when near0 already sits further down than that — else the bleed option is
|
|
220
|
+
* unavailable.
|
|
221
|
+
* `none` → always clear. `deep` → grow toward `deepBleed` (≥ `minBleed` at the width cap, ≥ `deepBleed`
|
|
222
|
+
* whenever growth alone reaches it), or the most the focus allows, else clear.
|
|
214
223
|
* `auto` → keep the natural placement when it already clears by the margin or is a focus-safe
|
|
215
224
|
* decisive bleed; otherwise (the tangent zone) PREFER the bleed option, and fall back to clear only
|
|
216
225
|
* when every ≥ `minBleed` bleed would crop the focus band. `preferBleed` (tilt) also turns a natural
|
|
@@ -240,24 +249,36 @@ export function solveVertical(inp: VerticalInput): VerticalResult {
|
|
|
240
249
|
return make(s, near0, s < s0 - EPS ? 'shrunk to clear the edge with a margin' : 'clears the edge');
|
|
241
250
|
};
|
|
242
251
|
|
|
243
|
-
/**
|
|
252
|
+
/**
|
|
253
|
+
* Smallest move reaching overshoot ≥ t·height, then made focus-safe (null if impossible). Growing
|
|
254
|
+
* the subject (up to its size cap — the width cap, or a tighter `scaleCap` when one binds) is
|
|
255
|
+
* always tried first. Only when that growth is capped short of t does the subject shift toward the
|
|
256
|
+
* far edge — and even then, only far enough for a decisive (`minBleed`) overshoot, never all the
|
|
257
|
+
* way to t: a deeper target like `deepBleed` is something to grow toward, not something worth
|
|
258
|
+
* shifting the subject away from the text to force.
|
|
259
|
+
*/
|
|
244
260
|
const bleedOption = (t: number): VerticalResult | null => {
|
|
245
261
|
let s = s0;
|
|
246
262
|
let a = near0;
|
|
247
263
|
if (overshoot(s, a) < t * s * eh - EPS) {
|
|
248
264
|
const need = (H - a) / ((1 - t) * eh);
|
|
249
265
|
s = Math.max(s0, Math.min(need, Math.max(sCap, s0)));
|
|
250
|
-
if (overshoot(s, a) <
|
|
266
|
+
if (overshoot(s, a) < NO_TANGENT.minBleed * s * eh - EPS) a = H - s * eh * (1 - NO_TANGENT.minBleed);
|
|
251
267
|
}
|
|
252
|
-
|
|
268
|
+
const reason =
|
|
269
|
+
overshoot(s, a) >= t * s * eh - EPS
|
|
270
|
+
? `bleeds ${Math.round(t * 100)}%+`
|
|
271
|
+
: `grows to its size cap (no gap forced to reach ${Math.round(t * 100)}%+)`;
|
|
272
|
+
if (focusOk(s, a)) return make(s, a, reason);
|
|
253
273
|
// Focus-constrained: keep the scale (≤ what the focus allows at near0) and bleed only as deep
|
|
254
|
-
// as the focus band allows — accepted if that is still a decisive (≥ minBleed) bleed.
|
|
274
|
+
// as the focus band allows — accepted if that is still a decisive (≥ minBleed) bleed. The shift
|
|
275
|
+
// itself only ever targets minBleed (never t), for the same no-gap reason as above.
|
|
255
276
|
if (inp.focusReach == null) return null;
|
|
256
277
|
const fr = inp.focusReach;
|
|
257
278
|
const sF = Math.min(s, Math.max(sCap, s0), (focusLimit - near0) / fr);
|
|
258
279
|
const denom = eh * (1 - NO_TANGENT.minBleed) - fr;
|
|
259
280
|
if (!(sF > 0) || denom <= 0 || sF < (H - focusLimit) / denom - EPS) return null;
|
|
260
|
-
const aF = Math.max(near0, Math.min(focusLimit - sF * fr, H - sF * eh * (1 -
|
|
281
|
+
const aF = Math.max(near0, Math.min(focusLimit - sF * fr, H - sF * eh * (1 - NO_TANGENT.minBleed)));
|
|
261
282
|
if (overshoot(sF, aF) < NO_TANGENT.minBleed * sF * eh - EPS || !focusOk(sF, aF)) return null;
|
|
262
283
|
return make(sF, aF, 'bleed reduced to keep the focus band visible');
|
|
263
284
|
};
|