appshot-cli 0.1.0

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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +381 -0
  3. package/bin/appshot.js +5 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +31 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/build.d.ts +3 -0
  9. package/dist/commands/build.d.ts.map +1 -0
  10. package/dist/commands/build.js +200 -0
  11. package/dist/commands/build.js.map +1 -0
  12. package/dist/commands/caption.d.ts +3 -0
  13. package/dist/commands/caption.d.ts.map +1 -0
  14. package/dist/commands/caption.js +118 -0
  15. package/dist/commands/caption.js.map +1 -0
  16. package/dist/commands/check.d.ts +3 -0
  17. package/dist/commands/check.d.ts.map +1 -0
  18. package/dist/commands/check.js +121 -0
  19. package/dist/commands/check.js.map +1 -0
  20. package/dist/commands/clean.d.ts +3 -0
  21. package/dist/commands/clean.d.ts.map +1 -0
  22. package/dist/commands/clean.js +133 -0
  23. package/dist/commands/clean.js.map +1 -0
  24. package/dist/commands/init.d.ts +3 -0
  25. package/dist/commands/init.d.ts.map +1 -0
  26. package/dist/commands/init.js +84 -0
  27. package/dist/commands/init.js.map +1 -0
  28. package/dist/commands/localize.d.ts +3 -0
  29. package/dist/commands/localize.d.ts.map +1 -0
  30. package/dist/commands/localize.js +31 -0
  31. package/dist/commands/localize.js.map +1 -0
  32. package/dist/commands/presets.d.ts +3 -0
  33. package/dist/commands/presets.d.ts.map +1 -0
  34. package/dist/commands/presets.js +135 -0
  35. package/dist/commands/presets.js.map +1 -0
  36. package/dist/commands/specs.d.ts +3 -0
  37. package/dist/commands/specs.d.ts.map +1 -0
  38. package/dist/commands/specs.js +69 -0
  39. package/dist/commands/specs.js.map +1 -0
  40. package/dist/commands/validate.d.ts +3 -0
  41. package/dist/commands/validate.d.ts.map +1 -0
  42. package/dist/commands/validate.js +183 -0
  43. package/dist/commands/validate.js.map +1 -0
  44. package/dist/core/app-store-specs.d.ts +55 -0
  45. package/dist/core/app-store-specs.d.ts.map +1 -0
  46. package/dist/core/app-store-specs.js +457 -0
  47. package/dist/core/app-store-specs.js.map +1 -0
  48. package/dist/core/compose.d.ts +30 -0
  49. package/dist/core/compose.d.ts.map +1 -0
  50. package/dist/core/compose.js +420 -0
  51. package/dist/core/compose.js.map +1 -0
  52. package/dist/core/devices.d.ts +50 -0
  53. package/dist/core/devices.d.ts.map +1 -0
  54. package/dist/core/devices.js +404 -0
  55. package/dist/core/devices.js.map +1 -0
  56. package/dist/core/files.d.ts +5 -0
  57. package/dist/core/files.d.ts.map +1 -0
  58. package/dist/core/files.js +35 -0
  59. package/dist/core/files.js.map +1 -0
  60. package/dist/core/frames-analyzer.d.ts +24 -0
  61. package/dist/core/frames-analyzer.d.ts.map +1 -0
  62. package/dist/core/frames-analyzer.js +97 -0
  63. package/dist/core/frames-analyzer.js.map +1 -0
  64. package/dist/core/frames-loader.d.ts +113 -0
  65. package/dist/core/frames-loader.d.ts.map +1 -0
  66. package/dist/core/frames-loader.js +440 -0
  67. package/dist/core/frames-loader.js.map +1 -0
  68. package/dist/core/mask-generator.d.ts +10 -0
  69. package/dist/core/mask-generator.d.ts.map +1 -0
  70. package/dist/core/mask-generator.js +99 -0
  71. package/dist/core/mask-generator.js.map +1 -0
  72. package/dist/core/render.d.ts +10 -0
  73. package/dist/core/render.d.ts.map +1 -0
  74. package/dist/core/render.js +92 -0
  75. package/dist/core/render.js.map +1 -0
  76. package/dist/core/text-renderer.d.ts +18 -0
  77. package/dist/core/text-renderer.d.ts.map +1 -0
  78. package/dist/core/text-renderer.js +148 -0
  79. package/dist/core/text-renderer.js.map +1 -0
  80. package/dist/types.d.ts +57 -0
  81. package/dist/types.d.ts.map +1 -0
  82. package/dist/types.js +2 -0
  83. package/dist/types.js.map +1 -0
  84. package/dist/utils/caption-history.d.ts +35 -0
  85. package/dist/utils/caption-history.d.ts.map +1 -0
  86. package/dist/utils/caption-history.js +233 -0
  87. package/dist/utils/caption-history.js.map +1 -0
  88. package/frames/Frames.json +308 -0
  89. package/frames/MacBook Air 2020.png +0 -0
  90. package/frames/MacBook Air 2022.png +0 -0
  91. package/frames/MacBook Pro 13.png +0 -0
  92. package/frames/MacBook Pro 2021 14.png +0 -0
  93. package/frames/MacBook Pro 2021 16.png +0 -0
  94. package/frames/Watch Series 10 42.png +0 -0
  95. package/frames/Watch Series 10 42_mask.png +0 -0
  96. package/frames/Watch Series 10 46.png +0 -0
  97. package/frames/Watch Series 10 46_mask.png +0 -0
  98. package/frames/Watch Series 4 40.png +0 -0
  99. package/frames/Watch Series 4 44.png +0 -0
  100. package/frames/Watch Series 7 41.png +0 -0
  101. package/frames/Watch Series 7 45.png +0 -0
  102. package/frames/Watch Ultra 2024.png +0 -0
  103. package/frames/iMac 2021.png +0 -0
  104. package/frames/iPad 2021 Landscape.png +0 -0
  105. package/frames/iPad 2021 Portrait.png +0 -0
  106. package/frames/iPad Air 2020 Landscape.png +0 -0
  107. package/frames/iPad Air 2020 Portrait.png +0 -0
  108. package/frames/iPad Pro 2018-2021 11 Landscape.png +0 -0
  109. package/frames/iPad Pro 2018-2021 11 Portrait.png +0 -0
  110. package/frames/iPad Pro 2018-2021 Landscape.png +0 -0
  111. package/frames/iPad Pro 2018-2021 Portrait.png +0 -0
  112. package/frames/iPad Pro 2024 11 Landscape.png +0 -0
  113. package/frames/iPad Pro 2024 11 Portrait.png +0 -0
  114. package/frames/iPad Pro 2024 13 Landscape.png +0 -0
  115. package/frames/iPad Pro 2024 13 Portrait.png +0 -0
  116. package/frames/iPad mini 2021 Landscape.png +0 -0
  117. package/frames/iPad mini 2021 Portrait.png +0 -0
  118. package/frames/iPhone 11 Landscape.png +0 -0
  119. package/frames/iPhone 11 Portrait.png +0 -0
  120. package/frames/iPhone 11 Pro Max Landscape.png +0 -0
  121. package/frames/iPhone 11 Pro Max Portrait.png +0 -0
  122. package/frames/iPhone 11 Pro Portrait.png +0 -0
  123. package/frames/iPhone 12-13 Pro Landscape.png +0 -0
  124. package/frames/iPhone 12-13 Pro Max Landscape.png +0 -0
  125. package/frames/iPhone 12-13 Pro Max Landscape_mask.png +0 -0
  126. package/frames/iPhone 12-13 Pro Max Portrait.png +0 -0
  127. package/frames/iPhone 12-13 Pro Max Portrait_mask.png +0 -0
  128. package/frames/iPhone 12-13 Pro Portrait.png +0 -0
  129. package/frames/iPhone 12-13 mini Landscape.png +0 -0
  130. package/frames/iPhone 12-13 mini Portrait.png +0 -0
  131. package/frames/iPhone 16 Landscape.png +0 -0
  132. package/frames/iPhone 16 Landscape_frame_no_island.png +0 -0
  133. package/frames/iPhone 16 Landscape_mask.png +0 -0
  134. package/frames/iPhone 16 Plus Landscape.png +0 -0
  135. package/frames/iPhone 16 Plus Landscape_frame_no_island.png +0 -0
  136. package/frames/iPhone 16 Plus Landscape_mask.png +0 -0
  137. package/frames/iPhone 16 Plus Portrait.png +0 -0
  138. package/frames/iPhone 16 Plus Portrait_frame_no_island.png +0 -0
  139. package/frames/iPhone 16 Plus Portrait_mask.png +0 -0
  140. package/frames/iPhone 16 Portrait.png +0 -0
  141. package/frames/iPhone 16 Portrait_frame_no_island.png +0 -0
  142. package/frames/iPhone 16 Portrait_mask.png +0 -0
  143. package/frames/iPhone 16 Pro Landscape.png +0 -0
  144. package/frames/iPhone 16 Pro Landscape_frame_no_island.png +0 -0
  145. package/frames/iPhone 16 Pro Landscape_mask.png +0 -0
  146. package/frames/iPhone 16 Pro Max Landscape.png +0 -0
  147. package/frames/iPhone 16 Pro Max Landscape_frame_no_island.png +0 -0
  148. package/frames/iPhone 16 Pro Max Landscape_mask.png +0 -0
  149. package/frames/iPhone 16 Pro Max Portrait.png +0 -0
  150. package/frames/iPhone 16 Pro Max Portrait_frame_no_island.png +0 -0
  151. package/frames/iPhone 16 Pro Max Portrait_mask.png +0 -0
  152. package/frames/iPhone 16 Pro Portrait.png +0 -0
  153. package/frames/iPhone 16 Pro Portrait_frame_no_island.png +0 -0
  154. package/frames/iPhone 16 Pro Portrait_mask.png +0 -0
  155. package/frames/iPhone 8 Plus Landscape.png +0 -0
  156. package/frames/iPhone 8 Plus Portrait.png +0 -0
  157. 2020 SE.png +0 -0
  158. package/frames/version.txt +1 -0
  159. package/package.json +61 -0
@@ -0,0 +1,99 @@
1
+ import sharp from 'sharp';
2
+ /**
3
+ * Generate a rounded rectangle mask without using SVG
4
+ * This creates a mask where white pixels are visible and black pixels are transparent
5
+ */
6
+ export async function generateRoundedRectMask(width, height, cornerRadius) {
7
+ // Create a raw pixel buffer for the mask
8
+ const channels = 4; // RGBA
9
+ const pixelCount = width * height;
10
+ const buffer = Buffer.alloc(pixelCount * channels);
11
+ // Fill the buffer with white pixels, making corners transparent
12
+ for (let y = 0; y < height; y++) {
13
+ for (let x = 0; x < width; x++) {
14
+ const offset = (y * width + x) * channels;
15
+ // Check if pixel is in a corner region
16
+ let inCorner = false;
17
+ // Top-left corner
18
+ if (x < cornerRadius && y < cornerRadius) {
19
+ const dx = cornerRadius - x;
20
+ const dy = cornerRadius - y;
21
+ const distance = Math.sqrt(dx * dx + dy * dy);
22
+ inCorner = distance > cornerRadius;
23
+ }
24
+ // Top-right corner
25
+ else if (x >= width - cornerRadius && y < cornerRadius) {
26
+ const dx = x - (width - cornerRadius);
27
+ const dy = cornerRadius - y;
28
+ const distance = Math.sqrt(dx * dx + dy * dy);
29
+ inCorner = distance > cornerRadius;
30
+ }
31
+ // Bottom-left corner
32
+ else if (x < cornerRadius && y >= height - cornerRadius) {
33
+ const dx = cornerRadius - x;
34
+ const dy = y - (height - cornerRadius);
35
+ const distance = Math.sqrt(dx * dx + dy * dy);
36
+ inCorner = distance > cornerRadius;
37
+ }
38
+ // Bottom-right corner
39
+ else if (x >= width - cornerRadius && y >= height - cornerRadius) {
40
+ const dx = x - (width - cornerRadius);
41
+ const dy = y - (height - cornerRadius);
42
+ const distance = Math.sqrt(dx * dx + dy * dy);
43
+ inCorner = distance > cornerRadius;
44
+ }
45
+ if (inCorner) {
46
+ // Transparent (black in mask)
47
+ buffer[offset] = 0; // R
48
+ buffer[offset + 1] = 0; // G
49
+ buffer[offset + 2] = 0; // B
50
+ buffer[offset + 3] = 0; // A
51
+ }
52
+ else {
53
+ // Visible (white in mask)
54
+ buffer[offset] = 255; // R
55
+ buffer[offset + 1] = 255; // G
56
+ buffer[offset + 2] = 255; // B
57
+ buffer[offset + 3] = 255; // A
58
+ }
59
+ }
60
+ }
61
+ // Convert raw buffer to PNG using Sharp
62
+ const mask = await sharp(buffer, {
63
+ raw: {
64
+ width: width,
65
+ height: height,
66
+ channels: 4
67
+ }
68
+ })
69
+ .png()
70
+ .toBuffer();
71
+ return mask;
72
+ }
73
+ /**
74
+ * Apply a rounded rectangle mask to an image
75
+ */
76
+ export async function applyRoundedCorners(imageBuffer, width, height, cornerRadius) {
77
+ if (cornerRadius <= 0) {
78
+ return imageBuffer;
79
+ }
80
+ try {
81
+ // Generate the mask
82
+ const mask = await generateRoundedRectMask(width, height, cornerRadius);
83
+ // Apply the mask using composite
84
+ const result = await sharp(imageBuffer)
85
+ .ensureAlpha()
86
+ .composite([{
87
+ input: mask,
88
+ blend: 'dest-in'
89
+ }])
90
+ .png()
91
+ .toBuffer();
92
+ return result;
93
+ }
94
+ catch (error) {
95
+ console.warn('Failed to apply rounded corners:', error);
96
+ return imageBuffer;
97
+ }
98
+ }
99
+ //# sourceMappingURL=mask-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask-generator.js","sourceRoot":"","sources":["../../src/core/mask-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { GradientConfig, CaptionConfig } from '../types.js';
2
+ export declare function renderGradient(width: number, height: number, config: GradientConfig): Promise<Buffer>;
3
+ export declare function addCaption(image: Buffer, text: string, config: CaptionConfig): Promise<Buffer>;
4
+ export declare function compositeScreenshot(screenshot: Buffer, frame: Buffer | null, frameMetadata?: {
5
+ screenX: number;
6
+ screenY: number;
7
+ screenWidth: number;
8
+ screenHeight: number;
9
+ }): Promise<Buffer>;
10
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjE,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,CAAC,CAyCjB;AAED,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,aAAa,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC9F,OAAO,CAAC,MAAM,CAAC,CAwBjB"}
@@ -0,0 +1,92 @@
1
+ import sharp from 'sharp';
2
+ import { createGradientBitmap } from './text-renderer.js';
3
+ export async function renderGradient(width, height, config) {
4
+ // Use bitmap gradient instead of SVG
5
+ const { colors, direction } = config;
6
+ // Use bitmap gradient instead of SVG - works without librsvg!
7
+ const directionMap = {
8
+ 'top-bottom': 'vertical',
9
+ 'bottom-top': 'vertical', // Will need to reverse colors
10
+ 'left-right': 'horizontal',
11
+ 'right-left': 'horizontal', // Will need to reverse colors
12
+ 'diagonal': 'diagonal'
13
+ };
14
+ const mappedDirection = directionMap[direction || 'top-bottom'] || 'vertical';
15
+ let effectiveColors = [...colors];
16
+ // Reverse colors for bottom-top or right-left
17
+ if (direction === 'bottom-top' || direction === 'right-left') {
18
+ effectiveColors = effectiveColors.reverse();
19
+ }
20
+ return await createGradientBitmap(width, height, effectiveColors, mappedDirection);
21
+ }
22
+ export async function addCaption(image, text, config) {
23
+ if (!text)
24
+ return image;
25
+ const metadata = await sharp(image).metadata();
26
+ const width = metadata.width || 1000;
27
+ const height = metadata.height || 1000;
28
+ // Create text as SVG
29
+ const textY = config.paddingTop + config.fontsize;
30
+ let textAnchor = 'middle';
31
+ let textX = width / 2;
32
+ if (config.align === 'left') {
33
+ textAnchor = 'start';
34
+ textX = config.paddingLeft || 50;
35
+ }
36
+ else if (config.align === 'right') {
37
+ textAnchor = 'end';
38
+ textX = width - (config.paddingRight || 50);
39
+ }
40
+ const svg = `
41
+ <svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
42
+ <text
43
+ x="${textX}"
44
+ y="${textY}"
45
+ font-family="${config.font}"
46
+ font-size="${config.fontsize}"
47
+ fill="${config.color}"
48
+ text-anchor="${textAnchor}"
49
+ >${escapeXml(text)}</text>
50
+ </svg>
51
+ `;
52
+ // Composite text over image
53
+ return sharp(image)
54
+ .composite([{
55
+ input: Buffer.from(svg),
56
+ top: 0,
57
+ left: 0
58
+ }])
59
+ .toBuffer();
60
+ }
61
+ export async function compositeScreenshot(screenshot, frame, frameMetadata) {
62
+ if (!frame)
63
+ return screenshot;
64
+ // Default frame metadata (will be customized per device)
65
+ const meta = frameMetadata || {
66
+ screenX: 100,
67
+ screenY: 200,
68
+ screenWidth: 1084,
69
+ screenHeight: 2378
70
+ };
71
+ // Resize screenshot to fit frame screen area
72
+ const resizedScreenshot = await sharp(screenshot)
73
+ .resize(meta.screenWidth, meta.screenHeight, { fit: 'fill' })
74
+ .toBuffer();
75
+ // Composite screenshot into frame
76
+ return sharp(frame)
77
+ .composite([{
78
+ input: resizedScreenshot,
79
+ left: meta.screenX,
80
+ top: meta.screenY
81
+ }])
82
+ .toBuffer();
83
+ }
84
+ function escapeXml(text) {
85
+ return text
86
+ .replace(/&/g, '&amp;')
87
+ .replace(/</g, '&lt;')
88
+ .replace(/>/g, '&gt;')
89
+ .replace(/"/g, '&quot;')
90
+ .replace(/'/g, '&apos;');
91
+ }
92
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Render text by creating a bitmap with text
3
+ * This works without SVG or any external dependencies
4
+ */
5
+ export declare function renderTextBitmap(text: string, width: number, height: number, _config: {
6
+ fontsize: number;
7
+ color: string;
8
+ align?: 'left' | 'center' | 'right';
9
+ paddingTop: number;
10
+ paddingLeft?: number;
11
+ paddingRight?: number;
12
+ font?: string;
13
+ }): Promise<Buffer>;
14
+ /**
15
+ * Create a gradient using pure bitmap manipulation
16
+ */
17
+ export declare function createGradientBitmap(width: number, height: number, colors: string[], direction?: 'vertical' | 'horizontal' | 'diagonal'): Promise<Buffer>;
18
+ //# sourceMappingURL=text-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-renderer.d.ts","sourceRoot":"","sources":["../../src/core/text-renderer.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACA,OAAO,CAAC,MAAM,CAAC,CA+CjB;AAuDD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EAAE,EAChB,SAAS,GAAE,UAAU,GAAG,YAAY,GAAG,UAAuB,GAC7D,OAAO,CAAC,MAAM,CAAC,CAsDjB"}
@@ -0,0 +1,148 @@
1
+ import sharp from 'sharp';
2
+ /**
3
+ * Render text by creating a bitmap with text
4
+ * This works without SVG or any external dependencies
5
+ */
6
+ export async function renderTextBitmap(text, width, height, _config) {
7
+ // Validate and sanitize color to prevent XSS
8
+ const _validateColor = (color) => {
9
+ // Remove any whitespace and convert to lowercase
10
+ const clean = color.trim().toLowerCase();
11
+ // Check if it's a valid hex color
12
+ const hexPattern = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/;
13
+ if (hexPattern.test(clean)) {
14
+ return clean.startsWith('#') ? clean : `#${clean}`;
15
+ }
16
+ // Check if it's a valid named color (basic set)
17
+ const namedColors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'gray', 'grey'];
18
+ if (namedColors.includes(clean)) {
19
+ return clean;
20
+ }
21
+ // Default to black if invalid
22
+ console.warn(`Invalid color "${color}" provided, using default #000000`);
23
+ return '#000000';
24
+ };
25
+ // Create a transparent background
26
+ const background = await sharp({
27
+ create: {
28
+ width,
29
+ height,
30
+ channels: 4,
31
+ background: { r: 0, g: 0, b: 0, alpha: 0 }
32
+ }
33
+ })
34
+ .png()
35
+ .toBuffer();
36
+ // Use Sharp's text annotation feature which doesn't require SVG
37
+ try {
38
+ // Simple text rendering without Pango to avoid dimension issues
39
+ // For now, just return the transparent background
40
+ // Text rendering with Pango requires librsvg which we're avoiding
41
+ return background;
42
+ }
43
+ catch {
44
+ console.log('[INFO] Text rendering using Pango not available, trying fallback...');
45
+ // Fallback: Return background without text but continue processing
46
+ return background;
47
+ }
48
+ }
49
+ function _escapeText(text) {
50
+ return text
51
+ .replace(/&/g, '&amp;')
52
+ .replace(/</g, '&lt;')
53
+ .replace(/>/g, '&gt;')
54
+ .replace(/"/g, '&quot;')
55
+ .replace(/'/g, '&apos;');
56
+ }
57
+ /**
58
+ * Wrap text to fit within a given width
59
+ */
60
+ function _wrapText(text, width, fontSize, maxLines = 3) {
61
+ // Estimate characters per line (rough approximation)
62
+ const charsPerLine = Math.floor(width / (fontSize * 0.45)); // Adjusted for better fit
63
+ if (text.length <= charsPerLine) {
64
+ return text;
65
+ }
66
+ // Simple word wrapping
67
+ const words = text.split(' ');
68
+ const lines = [];
69
+ let currentLine = '';
70
+ for (const word of words) {
71
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
72
+ if (testLine.length <= charsPerLine && lines.length < maxLines - 1) {
73
+ currentLine = testLine;
74
+ }
75
+ else {
76
+ if (currentLine && lines.length < maxLines) {
77
+ lines.push(currentLine);
78
+ }
79
+ currentLine = word;
80
+ }
81
+ // Stop if we've reached max lines
82
+ if (lines.length >= maxLines - 1 && currentLine) {
83
+ // Put remaining words on last line
84
+ const remainingWords = words.slice(words.indexOf(word));
85
+ lines.push(remainingWords.join(' '));
86
+ break;
87
+ }
88
+ }
89
+ if (currentLine && lines.length < maxLines) {
90
+ lines.push(currentLine);
91
+ }
92
+ // Join with newlines for Pango markup
93
+ return lines.slice(0, maxLines).join('\n');
94
+ }
95
+ /**
96
+ * Create a gradient using pure bitmap manipulation
97
+ */
98
+ export async function createGradientBitmap(width, height, colors, direction = 'vertical') {
99
+ // Parse hex colors
100
+ const parseHex = (hex) => {
101
+ const clean = hex.replace('#', '');
102
+ return {
103
+ r: parseInt(clean.slice(0, 2), 16),
104
+ g: parseInt(clean.slice(2, 4), 16),
105
+ b: parseInt(clean.slice(4, 6), 16)
106
+ };
107
+ };
108
+ const startColor = parseHex(colors[0] || '#6B46C1');
109
+ const endColor = parseHex(colors[colors.length - 1] || '#9333EA');
110
+ // Create raw pixel buffer for gradient
111
+ const channels = 3;
112
+ const pixelCount = width * height;
113
+ const buffer = Buffer.alloc(pixelCount * channels);
114
+ // Generate gradient pixels
115
+ for (let y = 0; y < height; y++) {
116
+ for (let x = 0; x < width; x++) {
117
+ let ratio;
118
+ if (direction === 'horizontal') {
119
+ ratio = x / width;
120
+ }
121
+ else if (direction === 'diagonal') {
122
+ ratio = (x + y) / (width + height);
123
+ }
124
+ else { // vertical
125
+ ratio = y / height;
126
+ }
127
+ // Linear interpolation between colors
128
+ const r = Math.round(startColor.r + (endColor.r - startColor.r) * ratio);
129
+ const g = Math.round(startColor.g + (endColor.g - startColor.g) * ratio);
130
+ const b = Math.round(startColor.b + (endColor.b - startColor.b) * ratio);
131
+ const offset = (y * width + x) * channels;
132
+ buffer[offset] = r;
133
+ buffer[offset + 1] = g;
134
+ buffer[offset + 2] = b;
135
+ }
136
+ }
137
+ // Convert raw buffer to PNG using Sharp
138
+ return await sharp(buffer, {
139
+ raw: {
140
+ width,
141
+ height,
142
+ channels
143
+ }
144
+ })
145
+ .png()
146
+ .toBuffer();
147
+ }
148
+ //# sourceMappingURL=text-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-renderer.js","sourceRoot":"","sources":["../../src/core/text-renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ export interface GradientConfig {
2
+ colors: string[];
3
+ direction: 'top-bottom' | 'bottom-top' | 'left-right' | 'right-left' | 'diagonal';
4
+ }
5
+ export interface CaptionConfig {
6
+ font: string;
7
+ fontsize: number;
8
+ color: string;
9
+ align: 'left' | 'center' | 'right';
10
+ paddingTop: number;
11
+ paddingBottom?: number;
12
+ paddingLeft?: number;
13
+ paddingRight?: number;
14
+ position?: 'overlay' | 'above';
15
+ }
16
+ export interface DeviceConfig {
17
+ input: string;
18
+ resolution: string;
19
+ frame?: string;
20
+ autoFrame?: boolean;
21
+ preferredFrame?: string;
22
+ partialFrame?: boolean;
23
+ frameOffset?: number;
24
+ }
25
+ export interface AppshotConfig {
26
+ output: string;
27
+ frames: string;
28
+ gradient: GradientConfig;
29
+ caption: CaptionConfig;
30
+ devices: {
31
+ [key: string]: DeviceConfig;
32
+ };
33
+ }
34
+ export interface CaptionEntry {
35
+ [lang: string]: string;
36
+ }
37
+ export interface CaptionsFile {
38
+ [filename: string]: string | CaptionEntry;
39
+ }
40
+ export interface CaptionSuggestions {
41
+ global: string[];
42
+ iphone?: string[];
43
+ ipad?: string[];
44
+ mac?: string[];
45
+ watch?: string[];
46
+ [device: string]: string[] | undefined;
47
+ }
48
+ export interface CaptionFrequency {
49
+ [caption: string]: number;
50
+ }
51
+ export interface CaptionHistory {
52
+ suggestions: CaptionSuggestions;
53
+ frequency: CaptionFrequency;
54
+ patterns: string[];
55
+ lastUpdated: string;
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,UAAU,CAAC;CACnF;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;CAC3C;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import type { CaptionHistory } from '../types.js';
2
+ /**
3
+ * Load caption history from file
4
+ */
5
+ export declare function loadCaptionHistory(): Promise<CaptionHistory>;
6
+ /**
7
+ * Save caption history to file
8
+ */
9
+ export declare function saveCaptionHistory(history: CaptionHistory): Promise<void>;
10
+ /**
11
+ * Update frequency count for a caption
12
+ */
13
+ export declare function updateFrequency(history: CaptionHistory, caption: string): void;
14
+ /**
15
+ * Add a caption to suggestions if it's new
16
+ */
17
+ export declare function addToSuggestions(history: CaptionHistory, caption: string, device?: string): void;
18
+ /**
19
+ * Extract patterns from a caption
20
+ * e.g., "Track your workouts" -> "Track your *"
21
+ */
22
+ export declare function extractPatterns(caption: string): string[];
23
+ /**
24
+ * Learn from existing caption files
25
+ */
26
+ export declare function learnFromExistingCaptions(history: CaptionHistory): Promise<void>;
27
+ /**
28
+ * Get suggestions for autocomplete
29
+ */
30
+ export declare function getSuggestions(history: CaptionHistory, device?: string, currentInput?: string): string[];
31
+ /**
32
+ * Clear caption history
33
+ */
34
+ export declare function clearCaptionHistory(): Promise<void>;
35
+ //# sourceMappingURL=caption-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caption-history.d.ts","sourceRoot":"","sources":["../../src/utils/caption-history.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAC;AAMpF;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC,CAmClE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK9E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAoBN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBzD;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAyCtF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,cAAc,EACvB,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,EAAE,CA8CV;AAmCD;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQzD"}