@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appshoteditor/shot-dsl",
3
- "version": "0.1.0",
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,
@@ -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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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.png',
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