@appshoteditor/shot-dsl 0.1.0 → 0.1.1
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/package.json +1 -1
- package/src/compose.ts +28 -3
- package/src/device-frames.ts +25 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appshoteditor/shot-dsl",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
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
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import type { BackgroundJSON, Template } from './types';
|
|
2
2
|
import { makeTextLayer, makeScreen, makeTemplate } from './builders';
|
|
3
3
|
import { makeDeviceFrameLayers } from './frames';
|
|
4
|
+
import { getDeviceFrame } from './device-frames';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Editor-unit canvas dimensions for a device, by frame class — so a plan that mixes iPhone, iPad,
|
|
8
|
+
* Android and Mac screens gets the right aspect per screen (multi-device). Matches the app's
|
|
9
|
+
* Page Setup presets (phone 280×608, tablet 450×600, laptop/desktop 608×380). Export scales these
|
|
10
|
+
* up to the real App Store pixel sizes.
|
|
11
|
+
*/
|
|
12
|
+
function canvasDimsForDevice(deviceId: string): { width: number; height: number } {
|
|
13
|
+
switch (getDeviceFrame(deviceId)?.category) {
|
|
14
|
+
case 'tablet':
|
|
15
|
+
return { width: 450, height: 600 };
|
|
16
|
+
case 'laptop':
|
|
17
|
+
case 'desktop':
|
|
18
|
+
return { width: 608, height: 380 };
|
|
19
|
+
case 'phone':
|
|
20
|
+
default:
|
|
21
|
+
return { width: 280, height: 608 };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
4
24
|
|
|
5
25
|
/** One screen's worth of plan input (the skill decides these per benefit). */
|
|
6
26
|
export interface ComposeScreenPlan {
|
|
@@ -25,10 +45,15 @@ export interface ComposePlan {
|
|
|
25
45
|
* plan (which benefit, copy, device, palette); this turns it into valid DSL.
|
|
26
46
|
*/
|
|
27
47
|
export function composeTemplate(plan: ComposePlan): Template {
|
|
28
|
-
const canvasWidth = plan.canvasWidth ?? 280;
|
|
29
|
-
const canvasHeight = plan.canvasHeight ?? 600;
|
|
30
|
-
|
|
31
48
|
const screens = plan.screens.map((screen) => {
|
|
49
|
+
// Per-screen canvas dims: honor explicit plan-level dims (backward compatible — same as the
|
|
50
|
+
// old single-size behavior), else derive from the screen's device class so a mixed-device
|
|
51
|
+
// plan gets the correct aspect per screen.
|
|
52
|
+
const explicit = plan.canvasWidth != null || plan.canvasHeight != null;
|
|
53
|
+
const { width: canvasWidth, height: canvasHeight } = explicit
|
|
54
|
+
? { width: plan.canvasWidth ?? 280, height: plan.canvasHeight ?? 600 }
|
|
55
|
+
: canvasDimsForDevice(screen.deviceId);
|
|
56
|
+
|
|
32
57
|
const { screenshot, frame } = makeDeviceFrameLayers({
|
|
33
58
|
deviceId: screen.deviceId,
|
|
34
59
|
screenshotUrl: screen.screenshot.url,
|
package/src/device-frames.ts
CHANGED
|
@@ -36,7 +36,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
36
36
|
name: 'iPhone 16 Pro',
|
|
37
37
|
platform: 'ios',
|
|
38
38
|
category: 'phone',
|
|
39
|
-
frameAsset: '/devices/iphone-16-pro.
|
|
39
|
+
frameAsset: '/devices/iphone-16-pro.webp',
|
|
40
40
|
imageDimensions: { width: 1406, height: 2822 },
|
|
41
41
|
// Screen centered within frame: (1406-1212)/2=97, (2822-2618)/2=102
|
|
42
42
|
screenBounds: { x: 97, y: 100, width: 1212, height: 2624 },
|
|
@@ -47,7 +47,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
47
47
|
name: 'iPhone 16 Pro Max',
|
|
48
48
|
platform: 'ios',
|
|
49
49
|
category: 'phone',
|
|
50
|
-
frameAsset: '/devices/iphone-16-pro-max.
|
|
50
|
+
frameAsset: '/devices/iphone-16-pro-max.webp',
|
|
51
51
|
imageDimensions: { width: 1520, height: 3068 },
|
|
52
52
|
// Screen centered within frame: (1520-1310)/2=105, (3068-2846)/2=111
|
|
53
53
|
screenBounds: { x: 100, y: 100, width: 1320, height: 2870 },
|
|
@@ -58,7 +58,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
58
58
|
name: 'iPhone 16',
|
|
59
59
|
platform: 'ios',
|
|
60
60
|
category: 'phone',
|
|
61
|
-
frameAsset: '/devices/iphone-16.
|
|
61
|
+
frameAsset: '/devices/iphone-16.webp',
|
|
62
62
|
imageDimensions: { width: 1379, height: 2756 },
|
|
63
63
|
screenBounds: { x: 95, y: 98, width: 1189, height: 2563 },
|
|
64
64
|
cornerRadius: 118
|
|
@@ -68,7 +68,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
68
68
|
name: 'iPhone 16 Plus',
|
|
69
69
|
platform: 'ios',
|
|
70
70
|
category: 'phone',
|
|
71
|
-
frameAsset: '/devices/iphone-16-plus.
|
|
71
|
+
frameAsset: '/devices/iphone-16-plus.webp',
|
|
72
72
|
imageDimensions: { width: 1490, height: 2996 },
|
|
73
73
|
screenBounds: { x: 103, y: 106, width: 1284, height: 2786 },
|
|
74
74
|
cornerRadius: 128
|
|
@@ -78,7 +78,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
78
78
|
name: 'iPhone 17 Pro',
|
|
79
79
|
platform: 'ios',
|
|
80
80
|
category: 'phone',
|
|
81
|
-
frameAsset: '/devices/iphone-17-pro.
|
|
81
|
+
frameAsset: '/devices/iphone-17-pro.webp',
|
|
82
82
|
imageDimensions: { width: 1406, height: 2822 },
|
|
83
83
|
screenBounds: { x: 97, y: 100, width: 1212, height: 2624 },
|
|
84
84
|
cornerRadius: 120
|
|
@@ -88,7 +88,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
88
88
|
name: 'iPhone 17 Pro Max',
|
|
89
89
|
platform: 'ios',
|
|
90
90
|
category: 'phone',
|
|
91
|
-
frameAsset: '/devices/iphone-17-pro-max.
|
|
91
|
+
frameAsset: '/devices/iphone-17-pro-max.webp',
|
|
92
92
|
imageDimensions: { width: 1520, height: 3068 },
|
|
93
93
|
screenBounds: { x: 100, y: 100, width: 1320, height: 2870 },
|
|
94
94
|
cornerRadius: 140
|
|
@@ -98,7 +98,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
98
98
|
name: 'iPhone Air',
|
|
99
99
|
platform: 'ios',
|
|
100
100
|
category: 'phone',
|
|
101
|
-
frameAsset: '/devices/iphone-air.
|
|
101
|
+
frameAsset: '/devices/iphone-air.webp',
|
|
102
102
|
imageDimensions: { width: 1490, height: 2996 },
|
|
103
103
|
screenBounds: { x: 103, y: 106, width: 1284, height: 2786 },
|
|
104
104
|
cornerRadius: 128
|
|
@@ -112,7 +112,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
112
112
|
name: 'Google Pixel 9 Pro',
|
|
113
113
|
platform: 'android',
|
|
114
114
|
category: 'phone',
|
|
115
|
-
frameAsset: '/devices/pixel-9-pro.
|
|
115
|
+
frameAsset: '/devices/pixel-9-pro.webp',
|
|
116
116
|
imageDimensions: { width: 1620, height: 3136 },
|
|
117
117
|
screenBounds: { x: 112, y: 111, width: 1396, height: 2916 },
|
|
118
118
|
cornerRadius: 135
|
|
@@ -122,7 +122,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
122
122
|
name: 'Google Pixel 9 Pro XL',
|
|
123
123
|
platform: 'android',
|
|
124
124
|
category: 'phone',
|
|
125
|
-
frameAsset: '/devices/pixel-9-pro-xl.
|
|
125
|
+
frameAsset: '/devices/pixel-9-pro-xl.webp',
|
|
126
126
|
imageDimensions: { width: 1684, height: 3272 },
|
|
127
127
|
screenBounds: { x: 116, y: 116, width: 1452, height: 3043 },
|
|
128
128
|
cornerRadius: 140
|
|
@@ -136,7 +136,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
136
136
|
name: 'iPad Pro 13" (M4)',
|
|
137
137
|
platform: 'ios',
|
|
138
138
|
category: 'tablet',
|
|
139
|
-
frameAsset: '/devices/ipad-pro-13-m4.
|
|
139
|
+
frameAsset: '/devices/ipad-pro-13-m4.webp',
|
|
140
140
|
imageDimensions: { width: 2264, height: 2952 },
|
|
141
141
|
screenBounds: { x: 100, y: 100, width: 2064, height: 2752 },
|
|
142
142
|
cornerRadius: 40
|
|
@@ -146,7 +146,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
146
146
|
name: 'iPad Pro 11" (M4)',
|
|
147
147
|
platform: 'ios',
|
|
148
148
|
category: 'tablet',
|
|
149
|
-
frameAsset: '/devices/ipad-pro-11-m4.
|
|
149
|
+
frameAsset: '/devices/ipad-pro-11-m4.webp',
|
|
150
150
|
imageDimensions: { width: 1868, height: 2620 },
|
|
151
151
|
screenBounds: { x: 100, y: 116, width: 1668, height: 2388 },
|
|
152
152
|
cornerRadius: 40
|
|
@@ -156,7 +156,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
156
156
|
name: 'iPad Air 13"',
|
|
157
157
|
platform: 'ios',
|
|
158
158
|
category: 'tablet',
|
|
159
|
-
frameAsset: '/devices/ipad-air-13.
|
|
159
|
+
frameAsset: '/devices/ipad-air-13.webp',
|
|
160
160
|
imageDimensions: { width: 2248, height: 2932 },
|
|
161
161
|
screenBounds: { x: 100, y: 100, width: 2048, height: 2732 },
|
|
162
162
|
cornerRadius: 40
|
|
@@ -166,7 +166,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
166
166
|
name: 'iPad Air 11"',
|
|
167
167
|
platform: 'ios',
|
|
168
168
|
category: 'tablet',
|
|
169
|
-
frameAsset: '/devices/ipad-air-11.
|
|
169
|
+
frameAsset: '/devices/ipad-air-11.webp',
|
|
170
170
|
imageDimensions: { width: 1880, height: 2600 },
|
|
171
171
|
screenBounds: { x: 120, y: 120, width: 1640, height: 2360 },
|
|
172
172
|
cornerRadius: 40
|
|
@@ -176,7 +176,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
176
176
|
name: 'iPad mini 7',
|
|
177
177
|
platform: 'ios',
|
|
178
178
|
category: 'tablet',
|
|
179
|
-
frameAsset: '/devices/ipad-mini-7.
|
|
179
|
+
frameAsset: '/devices/ipad-mini-7.webp',
|
|
180
180
|
imageDimensions: { width: 1888, height: 2666 },
|
|
181
181
|
screenBounds: { x: 200, y: 200, width: 1488, height: 2266 },
|
|
182
182
|
cornerRadius: 40
|
|
@@ -190,7 +190,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
190
190
|
name: 'MacBook Air 13"',
|
|
191
191
|
platform: 'macos',
|
|
192
192
|
category: 'laptop',
|
|
193
|
-
frameAsset: '/devices/macbook-air-13.
|
|
193
|
+
frameAsset: '/devices/macbook-air-13.webp',
|
|
194
194
|
imageDimensions: { width: 3260, height: 2164 },
|
|
195
195
|
screenBounds: { x: 350, y: 306, width: 2560, height: 1608 },
|
|
196
196
|
cornerRadius: 20
|
|
@@ -200,7 +200,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
200
200
|
name: 'MacBook Air 13" (Menu Bar)',
|
|
201
201
|
platform: 'macos',
|
|
202
202
|
category: 'laptop',
|
|
203
|
-
frameAsset: '/devices/macbook-air-13-menu-bar.
|
|
203
|
+
frameAsset: '/devices/macbook-air-13-menu-bar.webp',
|
|
204
204
|
imageDimensions: { width: 3260, height: 2164 },
|
|
205
205
|
screenBounds: { x: 350, y: 312, width: 2560, height: 1602 },
|
|
206
206
|
cornerRadius: 20
|
|
@@ -210,7 +210,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
210
210
|
name: 'MacBook Air 15"',
|
|
211
211
|
platform: 'macos',
|
|
212
212
|
category: 'laptop',
|
|
213
|
-
frameAsset: '/devices/macbook-air-15.
|
|
213
|
+
frameAsset: '/devices/macbook-air-15.webp',
|
|
214
214
|
imageDimensions: { width: 3580, height: 2364 },
|
|
215
215
|
screenBounds: { x: 350, y: 306, width: 2880, height: 1808 },
|
|
216
216
|
cornerRadius: 20
|
|
@@ -220,7 +220,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
220
220
|
name: 'MacBook Air 15" (Menu Bar)',
|
|
221
221
|
platform: 'macos',
|
|
222
222
|
category: 'laptop',
|
|
223
|
-
frameAsset: '/devices/macbook-air-15-menu-bar.
|
|
223
|
+
frameAsset: '/devices/macbook-air-15-menu-bar.webp',
|
|
224
224
|
imageDimensions: { width: 3580, height: 2364 },
|
|
225
225
|
screenBounds: { x: 350, y: 308, width: 2880, height: 1806 },
|
|
226
226
|
cornerRadius: 20
|
|
@@ -230,7 +230,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
230
230
|
name: 'MacBook Pro 14"',
|
|
231
231
|
platform: 'macos',
|
|
232
232
|
category: 'laptop',
|
|
233
|
-
frameAsset: '/devices/macbook-pro-14.
|
|
233
|
+
frameAsset: '/devices/macbook-pro-14.webp',
|
|
234
234
|
imageDimensions: { width: 3944, height: 2564 },
|
|
235
235
|
screenBounds: { x: 461, y: 364, width: 3022, height: 1900 },
|
|
236
236
|
cornerRadius: 20
|
|
@@ -240,7 +240,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
240
240
|
name: 'MacBook Pro 14" (Menu Bar)',
|
|
241
241
|
platform: 'macos',
|
|
242
242
|
category: 'laptop',
|
|
243
|
-
frameAsset: '/devices/macbook-pro-14-menu-bar.
|
|
243
|
+
frameAsset: '/devices/macbook-pro-14-menu-bar.webp',
|
|
244
244
|
imageDimensions: { width: 3824, height: 2564 },
|
|
245
245
|
screenBounds: { x: 401, y: 374, width: 3022, height: 1890 },
|
|
246
246
|
cornerRadius: 20
|
|
@@ -250,7 +250,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
250
250
|
name: 'MacBook Pro 16"',
|
|
251
251
|
platform: 'macos',
|
|
252
252
|
category: 'laptop',
|
|
253
|
-
frameAsset: '/devices/macbook-pro-16.
|
|
253
|
+
frameAsset: '/devices/macbook-pro-16.webp',
|
|
254
254
|
imageDimensions: { width: 4340, height: 2860 },
|
|
255
255
|
screenBounds: { x: 442, y: 377, width: 3456, height: 2170 },
|
|
256
256
|
cornerRadius: 20
|
|
@@ -260,7 +260,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
260
260
|
name: 'MacBook Pro 16" (Menu Bar)',
|
|
261
261
|
platform: 'macos',
|
|
262
262
|
category: 'laptop',
|
|
263
|
-
frameAsset: '/devices/macbook-pro-16-menu-bar.
|
|
263
|
+
frameAsset: '/devices/macbook-pro-16-menu-bar.webp',
|
|
264
264
|
imageDimensions: { width: 4340, height: 2860 },
|
|
265
265
|
screenBounds: { x: 442, y: 389, width: 3456, height: 2158 },
|
|
266
266
|
cornerRadius: 20
|
|
@@ -274,7 +274,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
274
274
|
name: 'iMac 24"',
|
|
275
275
|
platform: 'macos',
|
|
276
276
|
category: 'desktop',
|
|
277
|
-
frameAsset: '/devices/imac-24.
|
|
277
|
+
frameAsset: '/devices/imac-24.webp',
|
|
278
278
|
imageDimensions: { width: 4880, height: 5720 },
|
|
279
279
|
screenBounds: { x: 200, y: 1600, width: 4480, height: 2520 },
|
|
280
280
|
cornerRadius: 0
|
|
@@ -284,7 +284,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
284
284
|
name: 'Studio Display',
|
|
285
285
|
platform: 'macos',
|
|
286
286
|
category: 'desktop',
|
|
287
|
-
frameAsset: '/devices/studio-display.
|
|
287
|
+
frameAsset: '/devices/studio-display.webp',
|
|
288
288
|
imageDimensions: { width: 5520, height: 4316 },
|
|
289
289
|
screenBounds: { x: 200, y: 200, width: 5120, height: 2880 },
|
|
290
290
|
cornerRadius: 0
|
|
@@ -294,7 +294,7 @@ export const deviceFrames: DeviceFrame[] = [
|
|
|
294
294
|
name: 'Pro Display XDR',
|
|
295
295
|
platform: 'macos',
|
|
296
296
|
category: 'desktop',
|
|
297
|
-
frameAsset: '/devices/pro-display-xdr.
|
|
297
|
+
frameAsset: '/devices/pro-display-xdr.webp',
|
|
298
298
|
imageDimensions: { width: 6416, height: 4865 },
|
|
299
299
|
screenBounds: { x: 200, y: 200, width: 6016, height: 3384 },
|
|
300
300
|
cornerRadius: 0
|