opencode-nanobanana 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.
- package/.ralph-events.json +151 -0
- package/.ralph-last-branch +1 -0
- package/.ralph-monitor-state.json +7 -0
- package/.ralph-monitor.pid +1 -0
- package/.ralph-timing.json +26 -0
- package/README.md +708 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/platforms/android.d.ts +94 -0
- package/dist/platforms/android.d.ts.map +1 -0
- package/dist/platforms/android.js +123 -0
- package/dist/platforms/android.js.map +1 -0
- package/dist/platforms/ios.d.ts +51 -0
- package/dist/platforms/ios.d.ts.map +1 -0
- package/dist/platforms/ios.js +149 -0
- package/dist/platforms/ios.js.map +1 -0
- package/dist/platforms/macos.d.ts +33 -0
- package/dist/platforms/macos.d.ts.map +1 -0
- package/dist/platforms/macos.js +50 -0
- package/dist/platforms/macos.js.map +1 -0
- package/dist/platforms/watchos.d.ts +36 -0
- package/dist/platforms/watchos.d.ts.map +1 -0
- package/dist/platforms/watchos.js +113 -0
- package/dist/platforms/watchos.js.map +1 -0
- package/dist/platforms/web.d.ts +64 -0
- package/dist/platforms/web.d.ts.map +1 -0
- package/dist/platforms/web.js +96 -0
- package/dist/platforms/web.js.map +1 -0
- package/dist/providers/gemini.d.ts +41 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +177 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/tools/analyze/compare.d.ts +12 -0
- package/dist/tools/analyze/compare.d.ts.map +1 -0
- package/dist/tools/analyze/compare.js +83 -0
- package/dist/tools/analyze/compare.js.map +1 -0
- package/dist/tools/analyze/mockup.d.ts +12 -0
- package/dist/tools/analyze/mockup.d.ts.map +1 -0
- package/dist/tools/analyze/mockup.js +88 -0
- package/dist/tools/analyze/mockup.js.map +1 -0
- package/dist/tools/analyze/screenshot.d.ts +12 -0
- package/dist/tools/analyze/screenshot.d.ts.map +1 -0
- package/dist/tools/analyze/screenshot.js +61 -0
- package/dist/tools/analyze/screenshot.js.map +1 -0
- package/dist/tools/app-assets/app-icon.d.ts +9 -0
- package/dist/tools/app-assets/app-icon.d.ts.map +1 -0
- package/dist/tools/app-assets/app-icon.js +133 -0
- package/dist/tools/app-assets/app-icon.js.map +1 -0
- package/dist/tools/app-assets/device-mockup.d.ts +9 -0
- package/dist/tools/app-assets/device-mockup.d.ts.map +1 -0
- package/dist/tools/app-assets/device-mockup.js +139 -0
- package/dist/tools/app-assets/device-mockup.js.map +1 -0
- package/dist/tools/app-assets/launch-images.d.ts +3 -0
- package/dist/tools/app-assets/launch-images.d.ts.map +1 -0
- package/dist/tools/app-assets/launch-images.js +171 -0
- package/dist/tools/app-assets/launch-images.js.map +1 -0
- package/dist/tools/app-assets/resize-devices.d.ts +14 -0
- package/dist/tools/app-assets/resize-devices.d.ts.map +1 -0
- package/dist/tools/app-assets/resize-devices.js +296 -0
- package/dist/tools/app-assets/resize-devices.js.map +1 -0
- package/dist/tools/app-assets/screenshots.d.ts +14 -0
- package/dist/tools/app-assets/screenshots.d.ts.map +1 -0
- package/dist/tools/app-assets/screenshots.js +186 -0
- package/dist/tools/app-assets/screenshots.js.map +1 -0
- package/dist/tools/core/edit-image.d.ts +12 -0
- package/dist/tools/core/edit-image.d.ts.map +1 -0
- package/dist/tools/core/edit-image.js +102 -0
- package/dist/tools/core/edit-image.js.map +1 -0
- package/dist/tools/core/generate-image.d.ts +12 -0
- package/dist/tools/core/generate-image.d.ts.map +1 -0
- package/dist/tools/core/generate-image.js +96 -0
- package/dist/tools/core/generate-image.js.map +1 -0
- package/dist/tools/core/restore-image.d.ts +12 -0
- package/dist/tools/core/restore-image.d.ts.map +1 -0
- package/dist/tools/core/restore-image.js +104 -0
- package/dist/tools/core/restore-image.js.map +1 -0
- package/dist/tools/design/mockup-to-code.d.ts +3 -0
- package/dist/tools/design/mockup-to-code.d.ts.map +1 -0
- package/dist/tools/design/mockup-to-code.js +311 -0
- package/dist/tools/design/mockup-to-code.js.map +1 -0
- package/dist/tools/design/sketch-to-code.d.ts +3 -0
- package/dist/tools/design/sketch-to-code.d.ts.map +1 -0
- package/dist/tools/design/sketch-to-code.js +325 -0
- package/dist/tools/design/sketch-to-code.js.map +1 -0
- package/dist/tools/docs/architecture-diagram.d.ts +12 -0
- package/dist/tools/docs/architecture-diagram.d.ts.map +1 -0
- package/dist/tools/docs/architecture-diagram.js +179 -0
- package/dist/tools/docs/architecture-diagram.js.map +1 -0
- package/dist/tools/docs/readme-banner.d.ts +6 -0
- package/dist/tools/docs/readme-banner.d.ts.map +1 -0
- package/dist/tools/docs/readme-banner.js +108 -0
- package/dist/tools/docs/readme-banner.js.map +1 -0
- package/dist/tools/docs/sequence-diagram.d.ts +12 -0
- package/dist/tools/docs/sequence-diagram.d.ts.map +1 -0
- package/dist/tools/docs/sequence-diagram.js +161 -0
- package/dist/tools/docs/sequence-diagram.js.map +1 -0
- package/dist/tools/docs/social-preview.d.ts +11 -0
- package/dist/tools/docs/social-preview.d.ts.map +1 -0
- package/dist/tools/docs/social-preview.js +111 -0
- package/dist/tools/docs/social-preview.js.map +1 -0
- package/dist/tools/video/extend-video.d.ts +14 -0
- package/dist/tools/video/extend-video.d.ts.map +1 -0
- package/dist/tools/video/extend-video.js +39 -0
- package/dist/tools/video/extend-video.js.map +1 -0
- package/dist/tools/video/generate-video.d.ts +14 -0
- package/dist/tools/video/generate-video.d.ts.map +1 -0
- package/dist/tools/video/generate-video.js +39 -0
- package/dist/tools/video/generate-video.js.map +1 -0
- package/dist/tools/video/image-to-video.d.ts +15 -0
- package/dist/tools/video/image-to-video.d.ts.map +1 -0
- package/dist/tools/video/image-to-video.js +42 -0
- package/dist/tools/video/image-to-video.js.map +1 -0
- package/dist/tools/video/storyboard-video.d.ts +91 -0
- package/dist/tools/video/storyboard-video.d.ts.map +1 -0
- package/dist/tools/video/storyboard-video.js +230 -0
- package/dist/tools/video/storyboard-video.js.map +1 -0
- package/dist/utils/ffmpeg.d.ts +30 -0
- package/dist/utils/ffmpeg.d.ts.map +1 -0
- package/dist/utils/ffmpeg.js +205 -0
- package/dist/utils/ffmpeg.js.map +1 -0
- package/dist/utils/file-handler.d.ts +7 -0
- package/dist/utils/file-handler.d.ts.map +1 -0
- package/dist/utils/file-handler.js +10 -0
- package/dist/utils/file-handler.js.map +1 -0
- package/dist/utils/image-processing.d.ts +7 -0
- package/dist/utils/image-processing.d.ts.map +1 -0
- package/dist/utils/image-processing.js +10 -0
- package/dist/utils/image-processing.js.map +1 -0
- package/docs/PLUGIN-VERIFICATION.md +182 -0
- package/logs/notifications.jsonl +46 -0
- package/package.json +61 -0
- package/prd.json +216 -0
- package/progress.txt +145 -0
- package/ralph-report.html +297 -0
- package/src/index.ts +23 -0
- package/src/platforms/android/.gitkeep +0 -0
- package/src/platforms/ios/.gitkeep +0 -0
- package/src/platforms/web/.gitkeep +0 -0
- package/src/providers/.gitkeep +0 -0
- package/src/providers/gemini.ts +288 -0
- package/src/tools/core/.gitkeep +0 -0
- package/src/tools/platform/.gitkeep +0 -0
- package/src/tools/video/extend-video.ts +71 -0
- package/src/tools/video/generate-video.ts +70 -0
- package/src/tools/video/image-to-video.ts +76 -0
- package/src/tools/video/storyboard-video.ts +325 -0
- package/src/utils/.gitkeep +0 -0
- package/src/utils/ffmpeg.ts +266 -0
- package/src/utils/file-handler.ts +10 -0
- package/src/utils/image-processing.ts +10 -0
- package/templates/.gitkeep +0 -0
- package/test-analyze-screenshot.ts +50 -0
- package/test-app-icons.ts +55 -0
- package/test-cat-sunset.ts +30 -0
- package/test-full-plugin.ts +88 -0
- package/test-icon-gen.ts +30 -0
- package/test-output/test-edit.png +0 -0
- package/test-output/test-generate.png +0 -0
- package/test-output/test-video.mp4 +0 -0
- package/test-plugin-load.js +45 -0
- package/test-princess-emma-continue.ts +35 -0
- package/test-princess-emma-full.ts +38 -0
- package/test-princess-emma-short.ts +32 -0
- package/test-princess-emma-with-reference.ts +34 -0
- package/test-princess-emma.ts +38 -0
- package/test-product-ad.ts +66 -0
- package/test-ralph-droid.ts +30 -0
- package/test-social-preview.ts +61 -0
- package/test-veo31-live.ts +187 -0
- package/test-video-gen.ts +40 -0
- package/test-video-veo.ts +73 -0
- package/test-zurich-video.ts +64 -0
- package/tests/.gitkeep +0 -0
- package/tests/providers/gemini.test.ts +388 -0
- package/tests/utils/ffmpeg.test.ts +328 -0
- package/tests/video/storyboard.test.ts +469 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* watchOS Platform Specifications
|
|
3
|
+
*
|
|
4
|
+
* Defines icon sizes and specifications for Apple Watch apps across all watch sizes.
|
|
5
|
+
* Supports notification, home screen, short look, and App Store icons.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Complete watchOS icon sizes for all watch models and contexts
|
|
9
|
+
* Based on Apple's Human Interface Guidelines for watchOS
|
|
10
|
+
*/
|
|
11
|
+
export const WATCHOS_ICON_SIZES = [
|
|
12
|
+
// 38mm Apple Watch (Series 1, 2, 3)
|
|
13
|
+
{ size: 24, scale: 2, pixels: 48, context: 'notification', watchSize: '38mm', filename: 'Icon-Notification-38mm@2x.png' },
|
|
14
|
+
{ size: 27.5, scale: 2, pixels: 55, context: 'short-look', watchSize: '38mm', filename: 'Icon-ShortLook-38mm@2x.png' },
|
|
15
|
+
{ size: 40, scale: 2, pixels: 80, context: 'home', watchSize: '38mm', filename: 'Icon-Home-38mm@2x.png' },
|
|
16
|
+
{ size: 86, scale: 2, pixels: 172, context: 'short-look', watchSize: '38mm', filename: 'Icon-ShortLook-Large-38mm@2x.png' },
|
|
17
|
+
// 40mm Apple Watch (Series 4, 5, 6, SE)
|
|
18
|
+
{ size: 24, scale: 2, pixels: 48, context: 'notification', watchSize: '40mm', filename: 'Icon-Notification-40mm@2x.png' },
|
|
19
|
+
{ size: 27.5, scale: 2, pixels: 55, context: 'short-look', watchSize: '40mm', filename: 'Icon-ShortLook-40mm@2x.png' },
|
|
20
|
+
{ size: 40, scale: 2, pixels: 80, context: 'home', watchSize: '40mm', filename: 'Icon-Home-40mm@2x.png' },
|
|
21
|
+
{ size: 86, scale: 2, pixels: 172, context: 'short-look', watchSize: '40mm', filename: 'Icon-ShortLook-Large-40mm@2x.png' },
|
|
22
|
+
{ size: 92, scale: 2, pixels: 184, context: 'home', watchSize: '40mm', filename: 'Icon-Home-Large-40mm@2x.png' },
|
|
23
|
+
// 41mm Apple Watch (Series 7, 8, 9)
|
|
24
|
+
{ size: 24, scale: 2, pixels: 48, context: 'notification', watchSize: '41mm', filename: 'Icon-Notification-41mm@2x.png' },
|
|
25
|
+
{ size: 27.5, scale: 2, pixels: 55, context: 'short-look', watchSize: '41mm', filename: 'Icon-ShortLook-41mm@2x.png' },
|
|
26
|
+
{ size: 40, scale: 2, pixels: 80, context: 'home', watchSize: '41mm', filename: 'Icon-Home-41mm@2x.png' },
|
|
27
|
+
{ size: 86, scale: 2, pixels: 172, context: 'short-look', watchSize: '41mm', filename: 'Icon-ShortLook-Large-41mm@2x.png' },
|
|
28
|
+
{ size: 92, scale: 2, pixels: 184, context: 'home', watchSize: '41mm', filename: 'Icon-Home-Large-41mm@2x.png' },
|
|
29
|
+
// 42mm Apple Watch (Series 1, 2, 3)
|
|
30
|
+
{ size: 24, scale: 2, pixels: 48, context: 'notification', watchSize: '42mm', filename: 'Icon-Notification-42mm@2x.png' },
|
|
31
|
+
{ size: 27.5, scale: 2, pixels: 55, context: 'short-look', watchSize: '42mm', filename: 'Icon-ShortLook-42mm@2x.png' },
|
|
32
|
+
{ size: 44, scale: 2, pixels: 88, context: 'home', watchSize: '42mm', filename: 'Icon-Home-42mm@2x.png' },
|
|
33
|
+
{ size: 98, scale: 2, pixels: 196, context: 'short-look', watchSize: '42mm', filename: 'Icon-ShortLook-Large-42mm@2x.png' },
|
|
34
|
+
// 44mm Apple Watch (Series 4, 5, 6, SE)
|
|
35
|
+
{ size: 24, scale: 2, pixels: 48, context: 'notification', watchSize: '44mm', filename: 'Icon-Notification-44mm@2x.png' },
|
|
36
|
+
{ size: 27.5, scale: 2, pixels: 55, context: 'short-look', watchSize: '44mm', filename: 'Icon-ShortLook-44mm@2x.png' },
|
|
37
|
+
{ size: 44, scale: 2, pixels: 88, context: 'home', watchSize: '44mm', filename: 'Icon-Home-44mm@2x.png' },
|
|
38
|
+
{ size: 98, scale: 2, pixels: 196, context: 'short-look', watchSize: '44mm', filename: 'Icon-ShortLook-Large-44mm@2x.png' },
|
|
39
|
+
{ size: 100, scale: 2, pixels: 200, context: 'home', watchSize: '44mm', filename: 'Icon-Home-Large-44mm@2x.png' },
|
|
40
|
+
// 45mm Apple Watch (Series 7, 8, 9)
|
|
41
|
+
{ size: 24, scale: 2, pixels: 48, context: 'notification', watchSize: '45mm', filename: 'Icon-Notification-45mm@2x.png' },
|
|
42
|
+
{ size: 27.5, scale: 2, pixels: 55, context: 'short-look', watchSize: '45mm', filename: 'Icon-ShortLook-45mm@2x.png' },
|
|
43
|
+
{ size: 44, scale: 2, pixels: 88, context: 'home', watchSize: '45mm', filename: 'Icon-Home-45mm@2x.png' },
|
|
44
|
+
{ size: 98, scale: 2, pixels: 196, context: 'short-look', watchSize: '45mm', filename: 'Icon-ShortLook-Large-45mm@2x.png' },
|
|
45
|
+
{ size: 100, scale: 2, pixels: 200, context: 'home', watchSize: '45mm', filename: 'Icon-Home-Large-45mm@2x.png' },
|
|
46
|
+
// 49mm Apple Watch (Series 9, Ultra, Ultra 2)
|
|
47
|
+
{ size: 24, scale: 2, pixels: 48, context: 'notification', watchSize: '49mm', filename: 'Icon-Notification-49mm@2x.png' },
|
|
48
|
+
{ size: 27.5, scale: 2, pixels: 55, context: 'short-look', watchSize: '49mm', filename: 'Icon-ShortLook-49mm@2x.png' },
|
|
49
|
+
{ size: 44, scale: 2, pixels: 88, context: 'home', watchSize: '49mm', filename: 'Icon-Home-49mm@2x.png' },
|
|
50
|
+
{ size: 98, scale: 2, pixels: 196, context: 'short-look', watchSize: '49mm', filename: 'Icon-ShortLook-Large-49mm@2x.png' },
|
|
51
|
+
{ size: 108, scale: 2, pixels: 216, context: 'home', watchSize: '49mm', filename: 'Icon-Home-Large-49mm@2x.png' },
|
|
52
|
+
// App Store icon (1024x1024, universal)
|
|
53
|
+
{ size: 1024, scale: 1, pixels: 1024, context: 'store', watchSize: 'all', filename: 'Icon-AppStore-1024x1024.png' },
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* Generates Contents.json for Xcode watchOS asset catalog
|
|
57
|
+
*/
|
|
58
|
+
export function generateWatchContentsJson(sizes) {
|
|
59
|
+
const images = sizes.map(s => ({
|
|
60
|
+
filename: s.filename,
|
|
61
|
+
idiom: 'watch',
|
|
62
|
+
role: s.context,
|
|
63
|
+
scale: `${s.scale}x`,
|
|
64
|
+
size: `${s.size}x${s.size}`,
|
|
65
|
+
subtype: s.watchSize !== 'all' ? s.watchSize : undefined,
|
|
66
|
+
}));
|
|
67
|
+
return JSON.stringify({
|
|
68
|
+
images: images.filter(img => img.subtype !== undefined),
|
|
69
|
+
info: {
|
|
70
|
+
author: 'opencode-visual-toolkit',
|
|
71
|
+
version: 1,
|
|
72
|
+
},
|
|
73
|
+
}, null, 2);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Gets appropriate icon filename for watch size and context
|
|
77
|
+
*/
|
|
78
|
+
export function getWatchIconFilename(size, context, watchSize) {
|
|
79
|
+
if (size === 1024) {
|
|
80
|
+
return 'Icon-AppStore-1024x1024.png';
|
|
81
|
+
}
|
|
82
|
+
// Normalize context for filename
|
|
83
|
+
const contextMap = {
|
|
84
|
+
notification: 'Notification',
|
|
85
|
+
home: 'Home',
|
|
86
|
+
'short-look': 'ShortLook',
|
|
87
|
+
store: 'AppStore',
|
|
88
|
+
};
|
|
89
|
+
const contextName = contextMap[context] || context;
|
|
90
|
+
return `Icon-${contextName}-${watchSize}@2x.png`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Groups icon sizes by watch size for organized generation
|
|
94
|
+
*/
|
|
95
|
+
export function groupIconsByWatchSize() {
|
|
96
|
+
const grouped = {};
|
|
97
|
+
for (const iconSize of WATCHOS_ICON_SIZES) {
|
|
98
|
+
const key = iconSize.watchSize;
|
|
99
|
+
if (!grouped[key]) {
|
|
100
|
+
grouped[key] = [];
|
|
101
|
+
}
|
|
102
|
+
grouped[key].push(iconSize);
|
|
103
|
+
}
|
|
104
|
+
return grouped;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Gets all unique contexts (notification, home, short-look, store)
|
|
108
|
+
*/
|
|
109
|
+
export function getWatchContexts() {
|
|
110
|
+
const contexts = new Set(WATCHOS_ICON_SIZES.map(s => s.context));
|
|
111
|
+
return Array.from(contexts);
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=watchos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watchos.js","sourceRoot":"","sources":["../../src/platforms/watchos.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Platform Specifications
|
|
3
|
+
* Complete icon sizes for web applications including favicon and PWA icons
|
|
4
|
+
*/
|
|
5
|
+
export interface WebIconSize {
|
|
6
|
+
size: number;
|
|
7
|
+
purpose: 'favicon' | 'apple-touch' | 'pwa';
|
|
8
|
+
filename: string;
|
|
9
|
+
description: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Web Manifest Icon specification
|
|
13
|
+
* Used by PWA manifest.json
|
|
14
|
+
*/
|
|
15
|
+
export interface WebManifestIcon {
|
|
16
|
+
src: string;
|
|
17
|
+
sizes: string;
|
|
18
|
+
type: string;
|
|
19
|
+
purpose?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Complete web icon sizes
|
|
23
|
+
* Includes favicon (16, 32, 48), apple-touch-icon (180), PWA icons (192, 512)
|
|
24
|
+
*/
|
|
25
|
+
export declare const WEB_ICON_SIZES: WebIconSize[];
|
|
26
|
+
/**
|
|
27
|
+
* Generate Web Manifest icons array for manifest.json
|
|
28
|
+
* @param basePath Base path to icon directory (e.g., '/icons' or './icons')
|
|
29
|
+
* @returns Array of manifest icon objects
|
|
30
|
+
*/
|
|
31
|
+
export declare function generateWebManifestIcons(basePath?: string): WebManifestIcon[];
|
|
32
|
+
/**
|
|
33
|
+
* Generate favicon information
|
|
34
|
+
* Returns HTML link tags and .ico conversion instructions
|
|
35
|
+
* @returns Favicon configuration and HTML snippets
|
|
36
|
+
*/
|
|
37
|
+
export declare function generateFavicon(): {
|
|
38
|
+
sizes: WebIconSize[];
|
|
39
|
+
htmlSnippets: string[];
|
|
40
|
+
icoInstructions: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Get web icon filename based on purpose and size
|
|
44
|
+
* @param purpose Icon purpose (favicon, apple-touch, pwa)
|
|
45
|
+
* @param size Size in pixels
|
|
46
|
+
* @returns Filename string following web conventions
|
|
47
|
+
*/
|
|
48
|
+
export declare function getWebIconFilename(purpose: 'favicon' | 'apple-touch' | 'pwa', size: number): string;
|
|
49
|
+
/**
|
|
50
|
+
* Generate complete PWA manifest.json structure
|
|
51
|
+
* @param config PWA configuration
|
|
52
|
+
* @returns manifest.json object
|
|
53
|
+
*/
|
|
54
|
+
export declare function generatePWAManifest(config: {
|
|
55
|
+
name: string;
|
|
56
|
+
shortName: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
themeColor?: string;
|
|
59
|
+
backgroundColor?: string;
|
|
60
|
+
display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser';
|
|
61
|
+
orientation?: 'portrait' | 'landscape' | 'any';
|
|
62
|
+
iconBasePath?: string;
|
|
63
|
+
}): Record<string, unknown>;
|
|
64
|
+
//# sourceMappingURL=web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/platforms/web.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,GAAG,aAAa,GAAG,KAAK,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,WAAW,EAYvC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,MAAiB,GAAG,eAAe,EAAE,CASvF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI;IACjC,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB,CA4BA;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,GAAG,aAAa,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,SAAS,CAAC;IACjE,WAAW,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,KAAK,CAAC;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwB1B"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Platform Specifications
|
|
3
|
+
* Complete icon sizes for web applications including favicon and PWA icons
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Complete web icon sizes
|
|
7
|
+
* Includes favicon (16, 32, 48), apple-touch-icon (180), PWA icons (192, 512)
|
|
8
|
+
*/
|
|
9
|
+
export const WEB_ICON_SIZES = [
|
|
10
|
+
// Favicon sizes (for browsers)
|
|
11
|
+
{ size: 16, purpose: 'favicon', filename: 'favicon-16x16.png', description: 'Browser tab icon (small)' },
|
|
12
|
+
{ size: 32, purpose: 'favicon', filename: 'favicon-32x32.png', description: 'Browser tab icon (medium)' },
|
|
13
|
+
{ size: 48, purpose: 'favicon', filename: 'favicon-48x48.png', description: 'Browser tab icon (large)' },
|
|
14
|
+
// Apple Touch Icon
|
|
15
|
+
{ size: 180, purpose: 'apple-touch', filename: 'apple-touch-icon.png', description: 'iOS home screen icon' },
|
|
16
|
+
// PWA Icons (Progressive Web App)
|
|
17
|
+
{ size: 192, purpose: 'pwa', filename: 'icon-192x192.png', description: 'PWA icon (standard)' },
|
|
18
|
+
{ size: 512, purpose: 'pwa', filename: 'icon-512x512.png', description: 'PWA icon (large/splash)' },
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Generate Web Manifest icons array for manifest.json
|
|
22
|
+
* @param basePath Base path to icon directory (e.g., '/icons' or './icons')
|
|
23
|
+
* @returns Array of manifest icon objects
|
|
24
|
+
*/
|
|
25
|
+
export function generateWebManifestIcons(basePath = '/icons') {
|
|
26
|
+
const pwaIcons = WEB_ICON_SIZES.filter(icon => icon.purpose === 'pwa');
|
|
27
|
+
return pwaIcons.map(icon => ({
|
|
28
|
+
src: `${basePath}/${icon.filename}`,
|
|
29
|
+
sizes: `${icon.size}x${icon.size}`,
|
|
30
|
+
type: 'image/png',
|
|
31
|
+
purpose: 'any maskable', // Support both normal and maskable (Android adaptive)
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generate favicon information
|
|
36
|
+
* Returns HTML link tags and .ico conversion instructions
|
|
37
|
+
* @returns Favicon configuration and HTML snippets
|
|
38
|
+
*/
|
|
39
|
+
export function generateFavicon() {
|
|
40
|
+
const faviconSizes = WEB_ICON_SIZES.filter(icon => icon.purpose === 'favicon');
|
|
41
|
+
const appleTouchIcon = WEB_ICON_SIZES.find(icon => icon.purpose === 'apple-touch');
|
|
42
|
+
const htmlSnippets = [];
|
|
43
|
+
// Standard favicon.ico reference
|
|
44
|
+
htmlSnippets.push('<link rel="icon" href="/favicon.ico" sizes="any">');
|
|
45
|
+
// PNG favicons with size hints
|
|
46
|
+
faviconSizes.forEach(icon => {
|
|
47
|
+
htmlSnippets.push(`<link rel="icon" type="image/png" sizes="${icon.size}x${icon.size}" href="/${icon.filename}">`);
|
|
48
|
+
});
|
|
49
|
+
// Apple touch icon
|
|
50
|
+
if (appleTouchIcon) {
|
|
51
|
+
htmlSnippets.push(`<link rel="apple-touch-icon" href="/${appleTouchIcon.filename}">`);
|
|
52
|
+
}
|
|
53
|
+
// SVG favicon (modern browsers)
|
|
54
|
+
htmlSnippets.push('<link rel="icon" type="image/svg+xml" href="/favicon.svg">');
|
|
55
|
+
return {
|
|
56
|
+
sizes: faviconSizes,
|
|
57
|
+
htmlSnippets,
|
|
58
|
+
icoInstructions: 'To create favicon.ico: Use a multi-size ICO converter to combine 16x16, 32x32, and 48x48 PNG files into a single .ico file. Tools: ImageMagick (convert), online converters, or npm packages like png-to-ico.',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get web icon filename based on purpose and size
|
|
63
|
+
* @param purpose Icon purpose (favicon, apple-touch, pwa)
|
|
64
|
+
* @param size Size in pixels
|
|
65
|
+
* @returns Filename string following web conventions
|
|
66
|
+
*/
|
|
67
|
+
export function getWebIconFilename(purpose, size) {
|
|
68
|
+
if (purpose === 'apple-touch') {
|
|
69
|
+
return 'apple-touch-icon.png';
|
|
70
|
+
}
|
|
71
|
+
if (purpose === 'pwa') {
|
|
72
|
+
return `icon-${size}x${size}.png`;
|
|
73
|
+
}
|
|
74
|
+
return `favicon-${size}x${size}.png`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Generate complete PWA manifest.json structure
|
|
78
|
+
* @param config PWA configuration
|
|
79
|
+
* @returns manifest.json object
|
|
80
|
+
*/
|
|
81
|
+
export function generatePWAManifest(config) {
|
|
82
|
+
const { name, shortName, description = '', themeColor = '#000000', backgroundColor = '#ffffff', display = 'standalone', orientation = 'any', iconBasePath = '/icons', } = config;
|
|
83
|
+
return {
|
|
84
|
+
name,
|
|
85
|
+
short_name: shortName,
|
|
86
|
+
description,
|
|
87
|
+
theme_color: themeColor,
|
|
88
|
+
background_color: backgroundColor,
|
|
89
|
+
display,
|
|
90
|
+
orientation,
|
|
91
|
+
start_url: '/',
|
|
92
|
+
scope: '/',
|
|
93
|
+
icons: generateWebManifestIcons(iconBasePath),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/platforms/web.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,+BAA+B;IAC/B,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,mBAAmB,EAAE,WAAW,EAAE,0BAA0B,EAAE;IACxG,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,mBAAmB,EAAE,WAAW,EAAE,2BAA2B,EAAE;IACzG,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,mBAAmB,EAAE,WAAW,EAAE,0BAA0B,EAAE;IAExG,mBAAmB;IACnB,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,sBAAsB,EAAE,WAAW,EAAE,sBAAsB,EAAE;IAE5G,kCAAkC;IAClC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,EAAE,qBAAqB,EAAE;IAC/F,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,EAAE,yBAAyB,EAAE;CACpG,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAAmB,QAAQ;IAClE,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC;IAEvE,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3B,GAAG,EAAE,GAAG,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE;QACnC,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE;QAClC,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc,EAAE,sDAAsD;KAChF,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAK7B,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;IAC/E,MAAM,cAAc,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,aAAa,CAAC,CAAC;IAEnF,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,iCAAiC;IACjC,YAAY,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAEvE,+BAA+B;IAC/B,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAC1B,YAAY,CAAC,IAAI,CAAC,4CAA4C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,YAAY,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IACrH,CAAC,CAAC,CAAC;IAEH,mBAAmB;IACnB,IAAI,cAAc,EAAE,CAAC;QACnB,YAAY,CAAC,IAAI,CAAC,uCAAuC,cAAc,CAAC,QAAQ,IAAI,CAAC,CAAC;IACxF,CAAC;IAED,gCAAgC;IAChC,YAAY,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;IAEhF,OAAO;QACL,KAAK,EAAE,YAAY;QACnB,YAAY;QACZ,eAAe,EACb,+MAA+M;KAClN,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA0C,EAAE,IAAY;IACzF,IAAI,OAAO,KAAK,aAAa,EAAE,CAAC;QAC9B,OAAO,sBAAsB,CAAC;IAChC,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,QAAQ,IAAI,IAAI,IAAI,MAAM,CAAC;IACpC,CAAC;IACD,OAAO,WAAW,IAAI,IAAI,IAAI,MAAM,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,MASnC;IACC,MAAM,EACJ,IAAI,EACJ,SAAS,EACT,WAAW,GAAG,EAAE,EAChB,UAAU,GAAG,SAAS,EACtB,eAAe,GAAG,SAAS,EAC3B,OAAO,GAAG,YAAY,EACtB,WAAW,GAAG,KAAK,EACnB,YAAY,GAAG,QAAQ,GACxB,GAAG,MAAM,CAAC;IAEX,OAAO;QACL,IAAI;QACJ,UAAU,EAAE,SAAS;QACrB,WAAW;QACX,WAAW,EAAE,UAAU;QACvB,gBAAgB,EAAE,eAAe;QACjC,OAAO;QACP,WAAW;QACX,SAAS,EAAE,GAAG;QACd,KAAK,EAAE,GAAG;QACV,KAAK,EAAE,wBAAwB,CAAC,YAAY,CAAC;KAC9C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface VideoGenerationOptions {
|
|
2
|
+
aspectRatio?: '16:9' | '9:16';
|
|
3
|
+
resolution?: '720p' | '1080p';
|
|
4
|
+
duration?: 4 | 6 | 8;
|
|
5
|
+
numberOfVideos?: number;
|
|
6
|
+
negativePrompt?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ImageAnimationOptions {
|
|
9
|
+
aspectRatio?: '16:9' | '9:16';
|
|
10
|
+
resolution?: '720p' | '1080p';
|
|
11
|
+
duration?: 4 | 6 | 8;
|
|
12
|
+
}
|
|
13
|
+
export interface VideoExtensionOptions {
|
|
14
|
+
aspectRatio?: '16:9' | '9:16';
|
|
15
|
+
resolution?: '720p' | '1080p';
|
|
16
|
+
}
|
|
17
|
+
export interface ReferenceImage {
|
|
18
|
+
buffer: Buffer;
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
export interface VideoGenerationResult {
|
|
22
|
+
buffer: Buffer;
|
|
23
|
+
url?: string;
|
|
24
|
+
generationTime: number;
|
|
25
|
+
}
|
|
26
|
+
export declare class GeminiProvider {
|
|
27
|
+
private ai;
|
|
28
|
+
private apiKey;
|
|
29
|
+
private readonly VEO_MODEL;
|
|
30
|
+
private readonly VEO_PREVIEW_MODEL;
|
|
31
|
+
private readonly POLL_INTERVAL_MS;
|
|
32
|
+
constructor(apiKey: string);
|
|
33
|
+
generateVideo(prompt: string, options?: VideoGenerationOptions): Promise<VideoGenerationResult>;
|
|
34
|
+
animateImage(imageBuffer: Buffer, prompt: string, options?: ImageAnimationOptions): Promise<VideoGenerationResult>;
|
|
35
|
+
extendVideo(videoBuffer: Buffer, prompt: string, options?: VideoExtensionOptions): Promise<VideoGenerationResult>;
|
|
36
|
+
generateVideoWithReferences(prompt: string, referenceImages: ReferenceImage[], options?: VideoGenerationOptions): Promise<VideoGenerationResult>;
|
|
37
|
+
private pollOperation;
|
|
38
|
+
private downloadVideo;
|
|
39
|
+
private detectImageMimeType;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=gemini.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IACpD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA8B;IAChE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,MAAM,EAAE,MAAM;IAKpB,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC;IA0C3B,YAAY,CAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,qBAAqB,CAAC;IA8C3B,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,qBAAqB,CAAC;IA2C3B,2BAA2B,CAC/B,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,cAAc,EAAE,EACjC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC;YAqDnB,aAAa;YAab,aAAa;IAgB3B,OAAO,CAAC,mBAAmB;CAe5B"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { GoogleGenAI } from '@google/genai';
|
|
2
|
+
export class GeminiProvider {
|
|
3
|
+
ai;
|
|
4
|
+
apiKey;
|
|
5
|
+
VEO_MODEL = 'veo-3.0-generate-001';
|
|
6
|
+
VEO_PREVIEW_MODEL = 'veo-3.1-generate-preview';
|
|
7
|
+
POLL_INTERVAL_MS = 10000;
|
|
8
|
+
constructor(apiKey) {
|
|
9
|
+
this.apiKey = apiKey;
|
|
10
|
+
this.ai = new GoogleGenAI({ apiKey });
|
|
11
|
+
}
|
|
12
|
+
async generateVideo(prompt, options = {}) {
|
|
13
|
+
const startTime = Date.now();
|
|
14
|
+
const { aspectRatio = '16:9', resolution = '720p', duration = 8, numberOfVideos = 1, negativePrompt, } = options;
|
|
15
|
+
let operation = await this.ai.models.generateVideos({
|
|
16
|
+
model: this.VEO_MODEL,
|
|
17
|
+
prompt,
|
|
18
|
+
config: {
|
|
19
|
+
numberOfVideos,
|
|
20
|
+
aspectRatio,
|
|
21
|
+
resolution,
|
|
22
|
+
durationSeconds: duration,
|
|
23
|
+
...(negativePrompt && { negativePrompt }),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
operation = await this.pollOperation(operation);
|
|
27
|
+
if (!operation.response?.generatedVideos?.[0]) {
|
|
28
|
+
throw new Error('No video was generated');
|
|
29
|
+
}
|
|
30
|
+
const video = operation.response.generatedVideos[0];
|
|
31
|
+
const videoUrl = video.video?.uri;
|
|
32
|
+
if (!videoUrl) {
|
|
33
|
+
throw new Error('Video URL not available');
|
|
34
|
+
}
|
|
35
|
+
const buffer = await this.downloadVideo(videoUrl);
|
|
36
|
+
const generationTime = Date.now() - startTime;
|
|
37
|
+
return { buffer, url: videoUrl, generationTime };
|
|
38
|
+
}
|
|
39
|
+
async animateImage(imageBuffer, prompt, options = {}) {
|
|
40
|
+
const startTime = Date.now();
|
|
41
|
+
const { aspectRatio = '16:9', resolution = '720p', duration = 8, } = options;
|
|
42
|
+
const imageBase64 = imageBuffer.toString('base64');
|
|
43
|
+
const mimeType = this.detectImageMimeType(imageBuffer);
|
|
44
|
+
let operation = await this.ai.models.generateVideos({
|
|
45
|
+
model: this.VEO_MODEL,
|
|
46
|
+
prompt,
|
|
47
|
+
image: {
|
|
48
|
+
imageBytes: imageBase64,
|
|
49
|
+
mimeType,
|
|
50
|
+
},
|
|
51
|
+
config: {
|
|
52
|
+
numberOfVideos: 1,
|
|
53
|
+
aspectRatio,
|
|
54
|
+
resolution,
|
|
55
|
+
durationSeconds: duration,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
operation = await this.pollOperation(operation);
|
|
59
|
+
if (!operation.response?.generatedVideos?.[0]) {
|
|
60
|
+
throw new Error('No video was generated from image');
|
|
61
|
+
}
|
|
62
|
+
const video = operation.response.generatedVideos[0];
|
|
63
|
+
const videoUrl = video.video?.uri;
|
|
64
|
+
if (!videoUrl) {
|
|
65
|
+
throw new Error('Video URL not available');
|
|
66
|
+
}
|
|
67
|
+
const buffer = await this.downloadVideo(videoUrl);
|
|
68
|
+
const generationTime = Date.now() - startTime;
|
|
69
|
+
return { buffer, url: videoUrl, generationTime };
|
|
70
|
+
}
|
|
71
|
+
async extendVideo(videoBuffer, prompt, options = {}) {
|
|
72
|
+
const startTime = Date.now();
|
|
73
|
+
const { aspectRatio = '16:9', resolution = '720p', } = options;
|
|
74
|
+
const videoBase64 = videoBuffer.toString('base64');
|
|
75
|
+
let operation = await this.ai.models.generateVideos({
|
|
76
|
+
model: this.VEO_MODEL,
|
|
77
|
+
prompt,
|
|
78
|
+
video: {
|
|
79
|
+
videoBytes: videoBase64,
|
|
80
|
+
mimeType: 'video/mp4',
|
|
81
|
+
},
|
|
82
|
+
config: {
|
|
83
|
+
numberOfVideos: 1,
|
|
84
|
+
aspectRatio,
|
|
85
|
+
resolution,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
operation = await this.pollOperation(operation);
|
|
89
|
+
if (!operation.response?.generatedVideos?.[0]) {
|
|
90
|
+
throw new Error('Video extension failed');
|
|
91
|
+
}
|
|
92
|
+
const video = operation.response.generatedVideos[0];
|
|
93
|
+
const videoUrl = video.video?.uri;
|
|
94
|
+
if (!videoUrl) {
|
|
95
|
+
throw new Error('Video URL not available');
|
|
96
|
+
}
|
|
97
|
+
const buffer = await this.downloadVideo(videoUrl);
|
|
98
|
+
const generationTime = Date.now() - startTime;
|
|
99
|
+
return { buffer, url: videoUrl, generationTime };
|
|
100
|
+
}
|
|
101
|
+
async generateVideoWithReferences(prompt, referenceImages, options = {}) {
|
|
102
|
+
if (referenceImages.length === 0 || referenceImages.length > 3) {
|
|
103
|
+
throw new Error('Reference images must be between 1 and 3');
|
|
104
|
+
}
|
|
105
|
+
const startTime = Date.now();
|
|
106
|
+
const { aspectRatio = '16:9', resolution = '720p', duration = 8, numberOfVideos = 1, } = options;
|
|
107
|
+
const references = referenceImages.map((ref) => ({
|
|
108
|
+
image: {
|
|
109
|
+
imageBytes: ref.buffer.toString('base64'),
|
|
110
|
+
mimeType: this.detectImageMimeType(ref.buffer),
|
|
111
|
+
},
|
|
112
|
+
}));
|
|
113
|
+
let operation = await this.ai.models.generateVideos({
|
|
114
|
+
model: this.VEO_PREVIEW_MODEL,
|
|
115
|
+
prompt,
|
|
116
|
+
config: {
|
|
117
|
+
numberOfVideos,
|
|
118
|
+
aspectRatio,
|
|
119
|
+
resolution,
|
|
120
|
+
durationSeconds: duration,
|
|
121
|
+
referenceImages: references,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
operation = await this.pollOperation(operation);
|
|
125
|
+
if (!operation.response?.generatedVideos?.[0]) {
|
|
126
|
+
console.error('Operation response:', JSON.stringify(operation, null, 2));
|
|
127
|
+
throw new Error('No video was generated with references');
|
|
128
|
+
}
|
|
129
|
+
const video = operation.response.generatedVideos[0];
|
|
130
|
+
const videoUrl = video.video?.uri;
|
|
131
|
+
if (!videoUrl) {
|
|
132
|
+
throw new Error('Video URL not available');
|
|
133
|
+
}
|
|
134
|
+
const buffer = await this.downloadVideo(videoUrl);
|
|
135
|
+
const generationTime = Date.now() - startTime;
|
|
136
|
+
return { buffer, url: videoUrl, generationTime };
|
|
137
|
+
}
|
|
138
|
+
async pollOperation(operation) {
|
|
139
|
+
let currentOperation = operation;
|
|
140
|
+
while (!currentOperation.done) {
|
|
141
|
+
await new Promise((resolve) => setTimeout(resolve, this.POLL_INTERVAL_MS));
|
|
142
|
+
currentOperation = await this.ai.operations.getVideosOperation({
|
|
143
|
+
operation: currentOperation,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return currentOperation;
|
|
147
|
+
}
|
|
148
|
+
async downloadVideo(url) {
|
|
149
|
+
const response = await fetch(url, {
|
|
150
|
+
headers: {
|
|
151
|
+
'x-goog-api-key': this.apiKey,
|
|
152
|
+
},
|
|
153
|
+
redirect: 'follow',
|
|
154
|
+
});
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
throw new Error(`Failed to download video: ${response.statusText}`);
|
|
157
|
+
}
|
|
158
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
159
|
+
return Buffer.from(arrayBuffer);
|
|
160
|
+
}
|
|
161
|
+
detectImageMimeType(buffer) {
|
|
162
|
+
if (buffer[0] === 0xff && buffer[1] === 0xd8) {
|
|
163
|
+
return 'image/jpeg';
|
|
164
|
+
}
|
|
165
|
+
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
|
|
166
|
+
return 'image/png';
|
|
167
|
+
}
|
|
168
|
+
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46) {
|
|
169
|
+
return 'image/gif';
|
|
170
|
+
}
|
|
171
|
+
if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46) {
|
|
172
|
+
return 'image/webp';
|
|
173
|
+
}
|
|
174
|
+
return 'image/png';
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare Screenshots Tool
|
|
3
|
+
*
|
|
4
|
+
* Compares two screenshots to detect visual differences.
|
|
5
|
+
* Useful for visual regression testing and identifying UI changes.
|
|
6
|
+
*/
|
|
7
|
+
import { type ToolDefinition } from '@opencode-ai/plugin/tool';
|
|
8
|
+
/**
|
|
9
|
+
* Tool definition for compare_screenshots
|
|
10
|
+
*/
|
|
11
|
+
export declare const compareScreenshotsTool: ToolDefinition;
|
|
12
|
+
//# sourceMappingURL=compare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../../src/tools/analyze/compare.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAiBrE;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,cA8EnC,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare Screenshots Tool
|
|
3
|
+
*
|
|
4
|
+
* Compares two screenshots to detect visual differences.
|
|
5
|
+
* Useful for visual regression testing and identifying UI changes.
|
|
6
|
+
*/
|
|
7
|
+
import { tool } from '@opencode-ai/plugin/tool';
|
|
8
|
+
import { GeminiProvider } from '../../providers/gemini.js';
|
|
9
|
+
import { loadImage, saveImage, getOutputDir } from '../../utils/file-handler.js';
|
|
10
|
+
/**
|
|
11
|
+
* Tool args schema
|
|
12
|
+
*/
|
|
13
|
+
const compareScreenshotsArgs = {
|
|
14
|
+
imagePath1: tool.schema.string()
|
|
15
|
+
.describe('Path to the first screenshot image (baseline/before)'),
|
|
16
|
+
imagePath2: tool.schema.string()
|
|
17
|
+
.describe('Path to the second screenshot image (comparison/after)'),
|
|
18
|
+
highlightDifferences: tool.schema.boolean()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('If true, generate a visual diff image highlighting the differences. Default: false')
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Tool definition for compare_screenshots
|
|
24
|
+
*/
|
|
25
|
+
export const compareScreenshotsTool = tool({
|
|
26
|
+
description: 'Compare two screenshots to detect visual differences. Returns a detailed description of changes. Optionally generates a visual diff image highlighting the differences.',
|
|
27
|
+
args: compareScreenshotsArgs,
|
|
28
|
+
async execute(args, _context) {
|
|
29
|
+
try {
|
|
30
|
+
const { imagePath1, imagePath2, highlightDifferences = false } = args;
|
|
31
|
+
// Initialize Gemini provider
|
|
32
|
+
const provider = new GeminiProvider();
|
|
33
|
+
// Load both screenshot images
|
|
34
|
+
const image1Buffer = await loadImage(imagePath1);
|
|
35
|
+
const image2Buffer = await loadImage(imagePath2);
|
|
36
|
+
// Build comparison prompt
|
|
37
|
+
const comparisonPrompt = 'Compare these two screenshots in detail. Identify and describe:\n' +
|
|
38
|
+
'1. Visual differences (layout, colors, text, images)\n' +
|
|
39
|
+
'2. Component changes (added, removed, or modified elements)\n' +
|
|
40
|
+
'3. Spacing and alignment differences\n' +
|
|
41
|
+
'4. Typography changes (font size, weight, color)\n' +
|
|
42
|
+
'5. Overall impact of the changes\n\n' +
|
|
43
|
+
'Be specific about locations and changes. If the images are identical, clearly state that.';
|
|
44
|
+
// Analyze the comparison using Gemini
|
|
45
|
+
// Note: Gemini's multi-image analysis requires sending both images in a single request
|
|
46
|
+
const analysis = await provider.analyzeMultipleImages([image1Buffer, image2Buffer], comparisonPrompt);
|
|
47
|
+
let resultMessage = `✓ Screenshot Comparison Complete
|
|
48
|
+
|
|
49
|
+
Image 1: ${imagePath1}
|
|
50
|
+
Image 2: ${imagePath2}
|
|
51
|
+
|
|
52
|
+
${analysis}`;
|
|
53
|
+
// Generate diff highlight image if requested
|
|
54
|
+
if (highlightDifferences) {
|
|
55
|
+
try {
|
|
56
|
+
// Create a prompt for Gemini to generate a visual diff
|
|
57
|
+
const diffPrompt = 'Create a visual difference image that highlights the changes between the two screenshots. ' +
|
|
58
|
+
'Use red/pink highlighting to mark areas that have changed. ' +
|
|
59
|
+
'Show both screenshots side by side with the differences clearly marked.';
|
|
60
|
+
const diffBuffer = await provider.editImage(image1Buffer, diffPrompt);
|
|
61
|
+
// Save the diff image
|
|
62
|
+
const outputDir = getOutputDir();
|
|
63
|
+
const diffPath = await saveImage(diffBuffer, outputDir, 'screenshot-diff', 0);
|
|
64
|
+
resultMessage += `\n\n✓ Visual diff image generated: ${diffPath}`;
|
|
65
|
+
}
|
|
66
|
+
catch (diffError) {
|
|
67
|
+
resultMessage += `\n\n⚠ Warning: Could not generate visual diff image: ${diffError instanceof Error ? diffError.message : String(diffError)}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return resultMessage;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error instanceof Error && error.message.includes('GEMINI_API_KEY')) {
|
|
74
|
+
return '✗ Error: GEMINI_API_KEY is not set. Please configure your API key in environment variables.';
|
|
75
|
+
}
|
|
76
|
+
if (error instanceof Error && (error.message.includes('ENOENT') || error.message.includes('no such file'))) {
|
|
77
|
+
return `✗ Error: Could not load one or both screenshots. Please verify the file paths exist:\n - ${args.imagePath1}\n - ${args.imagePath2}`;
|
|
78
|
+
}
|
|
79
|
+
return `✗ Error comparing screenshots: ${error instanceof Error ? error.message : String(error)}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../src/tools/analyze/compare.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAuB,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEjF;;GAEG;AACH,MAAM,sBAAsB,GAAG;IAC7B,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;SAC7B,QAAQ,CAAC,sDAAsD,CAAC;IACnE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;SAC7B,QAAQ,CAAC,wDAAwD,CAAC;IACrE,oBAAoB,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;SACxC,QAAQ,EAAE;SACV,QAAQ,CAAC,oFAAoF,CAAC;CACzF,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAmB,IAAI,CAAC;IACzD,WAAW,EAAE,yKAAyK;IAEtL,IAAI,EAAE,sBAAsB;IAE5B,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ;QAC1B,IAAI,CAAC;YACH,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;YAEtE,6BAA6B;YAC7B,MAAM,QAAQ,GAAG,IAAI,cAAc,EAAE,CAAC;YAEtC,8BAA8B;YAC9B,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;YAEjD,0BAA0B;YAC1B,MAAM,gBAAgB,GACpB,mEAAmE;gBACnE,wDAAwD;gBACxD,+DAA+D;gBAC/D,wCAAwC;gBACxC,oDAAoD;gBACpD,sCAAsC;gBACtC,2FAA2F,CAAC;YAE9F,sCAAsC;YACtC,uFAAuF;YACvF,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,qBAAqB,CACnD,CAAC,YAAY,EAAE,YAAY,CAAC,EAC5B,gBAAgB,CACjB,CAAC;YAEF,IAAI,aAAa,GAAG;;WAEf,UAAU;WACV,UAAU;;EAEnB,QAAQ,EAAE,CAAC;YAEP,6CAA6C;YAC7C,IAAI,oBAAoB,EAAE,CAAC;gBACzB,IAAI,CAAC;oBACH,uDAAuD;oBACvD,MAAM,UAAU,GACd,4FAA4F;wBAC5F,6DAA6D;wBAC7D,yEAAyE,CAAC;oBAE5E,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;oBAEtE,sBAAsB;oBACtB,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;oBACjC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,CAAC,CACF,CAAC;oBAEF,aAAa,IAAI,sCAAsC,QAAQ,EAAE,CAAC;gBACpE,CAAC;gBAAC,OAAO,SAAS,EAAE,CAAC;oBACnB,aAAa,IAAI,wDAAwD,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBAChJ,CAAC;YACH,CAAC;YAED,OAAO,aAAa,CAAC;QAEvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACvE,OAAO,6FAA6F,CAAC;YACvG,CAAC;YACD,IAAI,KAAK,YAAY,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;gBAC3G,OAAO,6FAA6F,IAAI,CAAC,UAAU,SAAS,IAAI,CAAC,UAAU,EAAE,CAAC;YAChJ,CAAC;YACD,OAAO,kCAAkC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACpG,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
|