mcp-hydrocoder-image 1.0.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 (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +454 -0
  3. package/bin/install-skills.js +115 -0
  4. package/dist/api/geminiClient.d.ts +57 -0
  5. package/dist/api/geminiClient.d.ts.map +1 -0
  6. package/dist/api/geminiClient.js +341 -0
  7. package/dist/api/geminiClient.js.map +1 -0
  8. package/dist/api/geminiTextClient.d.ts +44 -0
  9. package/dist/api/geminiTextClient.d.ts.map +1 -0
  10. package/dist/api/geminiTextClient.js +202 -0
  11. package/dist/api/geminiTextClient.js.map +1 -0
  12. package/dist/business/fileManager.d.ts +20 -0
  13. package/dist/business/fileManager.d.ts.map +1 -0
  14. package/dist/business/fileManager.js +76 -0
  15. package/dist/business/fileManager.js.map +1 -0
  16. package/dist/business/inputValidator.d.ts +44 -0
  17. package/dist/business/inputValidator.d.ts.map +1 -0
  18. package/dist/business/inputValidator.js +213 -0
  19. package/dist/business/inputValidator.js.map +1 -0
  20. package/dist/business/responseBuilder.d.ts +21 -0
  21. package/dist/business/responseBuilder.d.ts.map +1 -0
  22. package/dist/business/responseBuilder.js +166 -0
  23. package/dist/business/responseBuilder.js.map +1 -0
  24. package/dist/business/structuredPromptGenerator.d.ts +56 -0
  25. package/dist/business/structuredPromptGenerator.d.ts.map +1 -0
  26. package/dist/business/structuredPromptGenerator.js +218 -0
  27. package/dist/business/structuredPromptGenerator.js.map +1 -0
  28. package/dist/index.d.ts +12 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +30 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/server/errorHandler.d.ts +29 -0
  33. package/dist/server/errorHandler.d.ts.map +1 -0
  34. package/dist/server/errorHandler.js +99 -0
  35. package/dist/server/errorHandler.js.map +1 -0
  36. package/dist/server/mcpServer.d.ts +159 -0
  37. package/dist/server/mcpServer.d.ts.map +1 -0
  38. package/dist/server/mcpServer.js +434 -0
  39. package/dist/server/mcpServer.js.map +1 -0
  40. package/dist/server-main.d.ts +5 -0
  41. package/dist/server-main.d.ts.map +1 -0
  42. package/dist/server-main.js +37 -0
  43. package/dist/server-main.js.map +1 -0
  44. package/dist/types/mcp.d.ts +121 -0
  45. package/dist/types/mcp.d.ts.map +1 -0
  46. package/dist/types/mcp.js +22 -0
  47. package/dist/types/mcp.js.map +1 -0
  48. package/dist/types/result.d.ts +27 -0
  49. package/dist/types/result.d.ts.map +1 -0
  50. package/dist/types/result.js +27 -0
  51. package/dist/types/result.js.map +1 -0
  52. package/dist/utils/config.d.ts +29 -0
  53. package/dist/utils/config.d.ts.map +1 -0
  54. package/dist/utils/config.js +56 -0
  55. package/dist/utils/config.js.map +1 -0
  56. package/dist/utils/errors.d.ts +84 -0
  57. package/dist/utils/errors.d.ts.map +1 -0
  58. package/dist/utils/errors.js +215 -0
  59. package/dist/utils/errors.js.map +1 -0
  60. package/dist/utils/logger.d.ts +80 -0
  61. package/dist/utils/logger.d.ts.map +1 -0
  62. package/dist/utils/logger.js +186 -0
  63. package/dist/utils/logger.js.map +1 -0
  64. package/dist/utils/security.d.ts +50 -0
  65. package/dist/utils/security.d.ts.map +1 -0
  66. package/dist/utils/security.js +116 -0
  67. package/dist/utils/security.js.map +1 -0
  68. package/package.json +89 -0
  69. package/skills/image-generation/SKILL.md +131 -0
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Logger utility for structured logging with sensitive data filtering
3
+ * Provides consistent logging format across the application
4
+ */
5
+ import * as crypto from 'node:crypto';
6
+ /**
7
+ * Logger class for structured logging with sensitive data protection
8
+ */
9
+ export class Logger {
10
+ constructor() {
11
+ this.sensitivePatterns = [
12
+ /GEMINI_API_KEY=([^\s]+)/gi,
13
+ /api[_-]?key[^\s]*[:=]\s*([^\s]+)/gi,
14
+ /password[^\s]*[:=]\s*([^\s]+)/gi,
15
+ /bearer\s+([a-zA-Z0-9\-._~+/]+=*)/gi,
16
+ /secret[^\s]*[:=]\s*([^\s]+)/gi,
17
+ /token[^\s]*[:=]\s*([^\s]+)/gi,
18
+ ];
19
+ this.urlPatterns = [
20
+ /(https?:\/\/[^\s]+)/gi, // URLs - separate to handle differently
21
+ ];
22
+ this.filterPatterns = [
23
+ /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g, // Credit card numbers
24
+ /\b\d{3}-\d{2}-\d{4}\b/g, // SSN
25
+ /\b(?:\+?1[-.]?)?\(?\d{3}\)?[-.]?\d{3}[-.]?\d{4}\b/g, // Phone numbers
26
+ /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/gi, // Emails
27
+ ];
28
+ this.keyBasedSensitivePatterns = [
29
+ /api[_-]?key/i,
30
+ /gemini[_-]?api[_-]?key/i,
31
+ /secret/i,
32
+ /password/i,
33
+ /token/i,
34
+ /credential/i,
35
+ /bearer/i,
36
+ ];
37
+ // Initialize session ID once per logger instance
38
+ this.currentSessionId = this.generateId();
39
+ }
40
+ /**
41
+ * Log a debug message (only in development mode)
42
+ * @param context Context or module where the log originates
43
+ * @param message Log message
44
+ * @param metadata Optional metadata object
45
+ */
46
+ debug(context, message, metadata) {
47
+ if (process.env['NODE_ENV'] === 'production')
48
+ return;
49
+ this.writeLog('debug', context, message, metadata);
50
+ }
51
+ /**
52
+ * Log an info message
53
+ * @param context Context or module where the log originates
54
+ * @param message Log message
55
+ * @param metadata Optional metadata object
56
+ */
57
+ info(context, message, metadata) {
58
+ this.writeLog('info', context, message, metadata);
59
+ }
60
+ /**
61
+ * Log a warning message
62
+ * @param context Context or module where the log originates
63
+ * @param message Log message
64
+ * @param metadata Optional metadata object
65
+ */
66
+ warn(context, message, metadata) {
67
+ this.writeLog('warn', context, message, metadata);
68
+ }
69
+ /**
70
+ * Log an error message
71
+ * @param context Context or module where the log originates
72
+ * @param message Log message
73
+ * @param error Optional error object
74
+ * @param metadata Optional metadata object
75
+ */
76
+ error(context, message, error, metadata) {
77
+ const enhancedMetadata = {
78
+ ...metadata,
79
+ ...(error && {
80
+ errorName: error.name,
81
+ errorMessage: this.sanitizeString(error.message),
82
+ errorStack: process.env['NODE_ENV'] !== 'production' ? error.stack : undefined,
83
+ }),
84
+ };
85
+ this.writeLog('error', context, message, enhancedMetadata);
86
+ }
87
+ /**
88
+ * Core log writing method with structured format
89
+ */
90
+ writeLog(level, context, message, metadata) {
91
+ const logEntry = {
92
+ timestamp: new Date().toISOString(),
93
+ level,
94
+ context,
95
+ message: this.sanitizeString(message),
96
+ ...(metadata && { metadata: this.sanitizeMetadata(metadata) }),
97
+ traceId: this.getCurrentTraceId(),
98
+ sessionId: this.getCurrentSessionId(),
99
+ };
100
+ // JSON format structured log output
101
+ const logOutput = JSON.stringify(logEntry);
102
+ // For MCP servers, ALL logs must go to stderr
103
+ // stdout is reserved for JSON-RPC messages only
104
+ console.error(logOutput);
105
+ }
106
+ /**
107
+ * Sanitize string content by redacting sensitive information
108
+ * @param input String to sanitize
109
+ * @returns Sanitized string
110
+ */
111
+ sanitizeString(input) {
112
+ let sanitized = input;
113
+ // Redact sensitive data patterns (API keys, passwords, etc.)
114
+ for (const pattern of this.sensitivePatterns) {
115
+ sanitized = sanitized.replace(pattern, (match, group1) => match.replace(group1, '[REDACTED]'));
116
+ }
117
+ // Additional broad filter for API key-like strings in text
118
+ // Remove any reference to API key terms even in plain text
119
+ sanitized = sanitized.replace(/\bapi[_-]?key\b/gi, '[REDACTED]');
120
+ sanitized = sanitized.replace(/\bgemini[_-]?api[_-]?key\b/gi, '[REDACTED]');
121
+ // Remove long alphanumeric strings that might be API keys or secrets
122
+ sanitized = sanitized.replace(/\b[A-Za-z0-9]{20,}\b/g, '[REDACTED]');
123
+ // Redact URLs with specific label
124
+ for (const pattern of this.urlPatterns) {
125
+ sanitized = sanitized.replace(pattern, '[URL_REDACTED]');
126
+ }
127
+ // Filter personal information patterns
128
+ for (const pattern of this.filterPatterns) {
129
+ sanitized = sanitized.replace(pattern, '[FILTERED]');
130
+ }
131
+ return sanitized;
132
+ }
133
+ /**
134
+ * Sanitize metadata by redacting sensitive information
135
+ * @param metadata Metadata object to sanitize
136
+ * @returns Sanitized metadata object
137
+ */
138
+ sanitizeMetadata(metadata) {
139
+ const sanitized = {};
140
+ for (const [key, value] of Object.entries(metadata)) {
141
+ if (this.isSensitiveKey(key)) {
142
+ sanitized[key] = '[REDACTED]';
143
+ }
144
+ else if (typeof value === 'string') {
145
+ sanitized[key] = this.sanitizeString(value);
146
+ }
147
+ else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
148
+ sanitized[key] = this.sanitizeMetadata(value);
149
+ }
150
+ else {
151
+ sanitized[key] = value;
152
+ }
153
+ }
154
+ return sanitized;
155
+ }
156
+ /**
157
+ * Check if a key contains sensitive information
158
+ * @param key Object key to check
159
+ * @returns True if the key contains sensitive information
160
+ */
161
+ isSensitiveKey(key) {
162
+ return this.keyBasedSensitivePatterns.some((pattern) => pattern.test(key));
163
+ }
164
+ /**
165
+ * Generate unique ID for trace/session tracking
166
+ */
167
+ generateId() {
168
+ return crypto.randomUUID().substring(0, 8);
169
+ }
170
+ /**
171
+ * Get or generate current trace ID
172
+ */
173
+ getCurrentTraceId() {
174
+ if (!this.currentTraceId) {
175
+ this.currentTraceId = this.generateId();
176
+ }
177
+ return this.currentTraceId;
178
+ }
179
+ /**
180
+ * Get current session ID
181
+ */
182
+ getCurrentSessionId() {
183
+ return this.currentSessionId;
184
+ }
185
+ }
186
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Security Manager for file path validation and sanitization
3
+ * Provides protection against path traversal, null byte injection, and other security threats
4
+ */
5
+ import { type Result } from '../types/result.js';
6
+ import { SecurityError } from './errors.js';
7
+ /**
8
+ * Security manager for handling file path validation and sanitization
9
+ */
10
+ export declare class SecurityManager {
11
+ private readonly allowedBasePaths;
12
+ /**
13
+ * Sanitize and validate file path for security
14
+ * @param inputPath File path to sanitize
15
+ * @returns Result containing sanitized path or security error
16
+ */
17
+ sanitizeFilePath(inputPath: string): Result<string, SecurityError>;
18
+ /**
19
+ * Validate image file extension
20
+ * @param filePath File path to validate
21
+ * @returns Result indicating validation success or security error
22
+ */
23
+ validateImageFile(filePath: string): Result<void, SecurityError>;
24
+ /**
25
+ * Validate directory path for security
26
+ * @param dirPath Directory path to validate
27
+ * @returns Result indicating validation success or security error
28
+ */
29
+ validateDirectoryPath(dirPath: string): Result<void, SecurityError>;
30
+ /**
31
+ * Generate secure temporary file path
32
+ * @param baseName Base name for the temporary file
33
+ * @param extension File extension (with dot)
34
+ * @returns Secure temporary file path
35
+ */
36
+ generateSecureTempPath(baseName: string, extension: string): string;
37
+ /**
38
+ * Check if a path is within allowed directories
39
+ * @param targetPath Path to check
40
+ * @returns True if path is within allowed directories
41
+ */
42
+ isPathAllowed(targetPath: string): boolean;
43
+ /**
44
+ * Sanitize filename by removing dangerous characters
45
+ * @param filename Filename to sanitize
46
+ * @returns Sanitized filename
47
+ */
48
+ sanitizeFilename(filename: string): string;
49
+ }
50
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/utils/security.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAMhC;IAED;;;;OAIG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC;IAwBlE;;;;OAIG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;IAYhE;;;;OAIG;IACH,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;IAUnE;;;;;OAKG;IACH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAQnE;;;;OAIG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAK1C;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAuB3C"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Security Manager for file path validation and sanitization
3
+ * Provides protection against path traversal, null byte injection, and other security threats
4
+ */
5
+ import * as path from 'node:path';
6
+ import { Err, Ok } from '../types/result.js';
7
+ import { SecurityError } from './errors.js';
8
+ /**
9
+ * Security manager for handling file path validation and sanitization
10
+ */
11
+ export class SecurityManager {
12
+ constructor() {
13
+ this.allowedBasePaths = [
14
+ process.cwd(),
15
+ path.resolve(process.env['IMAGE_OUTPUT_DIR'] || './output'),
16
+ path.resolve('./temp'),
17
+ path.resolve('./tmp'),
18
+ '/tmp',
19
+ ];
20
+ }
21
+ /**
22
+ * Sanitize and validate file path for security
23
+ * @param inputPath File path to sanitize
24
+ * @returns Result containing sanitized path or security error
25
+ */
26
+ sanitizeFilePath(inputPath) {
27
+ // Null byte attack prevention
28
+ if (inputPath.includes('\0')) {
29
+ return Err(new SecurityError('Null byte detected in file path'));
30
+ }
31
+ // Path traversal attack prevention
32
+ if (inputPath.includes('..')) {
33
+ return Err(new SecurityError('Path traversal attempt detected'));
34
+ }
35
+ // Resolve and validate absolute path
36
+ const resolvedPath = path.resolve(inputPath);
37
+ const isAllowed = this.allowedBasePaths.some((basePath) => resolvedPath.startsWith(path.resolve(basePath)));
38
+ if (!isAllowed) {
39
+ return Err(new SecurityError('File path outside allowed directories'));
40
+ }
41
+ return Ok(resolvedPath);
42
+ }
43
+ /**
44
+ * Validate image file extension
45
+ * @param filePath File path to validate
46
+ * @returns Result indicating validation success or security error
47
+ */
48
+ validateImageFile(filePath) {
49
+ // Allowed image file extensions
50
+ const allowedExtensions = ['.png', '.jpg', '.jpeg', '.webp'];
51
+ const extension = path.extname(filePath).toLowerCase();
52
+ if (!allowedExtensions.includes(extension)) {
53
+ return Err(new SecurityError(`Unsupported file extension: ${extension}`));
54
+ }
55
+ return Ok(undefined);
56
+ }
57
+ /**
58
+ * Validate directory path for security
59
+ * @param dirPath Directory path to validate
60
+ * @returns Result indicating validation success or security error
61
+ */
62
+ validateDirectoryPath(dirPath) {
63
+ // Use same security checks as file path validation
64
+ const pathValidation = this.sanitizeFilePath(dirPath);
65
+ if (!pathValidation.success) {
66
+ return pathValidation;
67
+ }
68
+ return Ok(undefined);
69
+ }
70
+ /**
71
+ * Generate secure temporary file path
72
+ * @param baseName Base name for the temporary file
73
+ * @param extension File extension (with dot)
74
+ * @returns Secure temporary file path
75
+ */
76
+ generateSecureTempPath(baseName, extension) {
77
+ const timestamp = Date.now();
78
+ const randomSuffix = Math.random().toString(36).substring(2, 8);
79
+ const secureFilename = `${baseName}-${timestamp}-${randomSuffix}${extension}`;
80
+ return path.join('/tmp', secureFilename);
81
+ }
82
+ /**
83
+ * Check if a path is within allowed directories
84
+ * @param targetPath Path to check
85
+ * @returns True if path is within allowed directories
86
+ */
87
+ isPathAllowed(targetPath) {
88
+ const resolvedPath = path.resolve(targetPath);
89
+ return this.allowedBasePaths.some((basePath) => resolvedPath.startsWith(path.resolve(basePath)));
90
+ }
91
+ /**
92
+ * Sanitize filename by removing dangerous characters
93
+ * @param filename Filename to sanitize
94
+ * @returns Sanitized filename
95
+ */
96
+ sanitizeFilename(filename) {
97
+ // Remove null bytes and path separators
98
+ let sanitized = filename.replace(/[\0/\\]/g, '');
99
+ // Remove control characters (ASCII 0-31 and 127) by filtering each character
100
+ sanitized = sanitized
101
+ .split('')
102
+ .filter((char) => {
103
+ const code = char.charCodeAt(0);
104
+ return code > 31 && code !== 127;
105
+ })
106
+ .join('');
107
+ // Trim whitespace and dots (to prevent hidden files and relative paths)
108
+ sanitized = sanitized.replace(/^\.+|\.+$/g, '').trim();
109
+ // Ensure filename is not empty after sanitization
110
+ if (sanitized.length === 0) {
111
+ sanitized = `secure-file-${Date.now()}`;
112
+ }
113
+ return sanitized;
114
+ }
115
+ }
116
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/utils/security.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "mcp-hydrocoder-image",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for AI image generation with multi-image support",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "mcp-hydrocoder-image": "./dist/index.js"
9
+ },
10
+ "keywords": [
11
+ "mcp",
12
+ "mcp-server",
13
+ "model-context-protocol",
14
+ "image-generation",
15
+ "generative-ai",
16
+ "image-editing",
17
+ "prompt-enhancement",
18
+ "gemini",
19
+ "google-ai",
20
+ "nano-banana",
21
+ "claude-code",
22
+ "cursor",
23
+ "codex",
24
+ "typescript",
25
+ "agent-skills",
26
+ "skills"
27
+ ],
28
+ "author": "Shinsuke Kagawa",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/ynzys/mcp-banana.git"
33
+ },
34
+ "files": [
35
+ "dist/**/*",
36
+ "!dist/**/*.test.js",
37
+ "!dist/**/*.test.d.ts",
38
+ "!dist/__tests__",
39
+ "!dist/tests",
40
+ "bin",
41
+ "skills"
42
+ ],
43
+ "scripts": {
44
+ "build": "tsc && tsc-alias",
45
+ "link": "npm run build && npm link",
46
+ "test": "vitest run",
47
+ "test:coverage": "vitest run --coverage",
48
+ "test:coverage:summary": "node scripts/show-coverage.js",
49
+ "test:coverage:clean": "rm -rf coverage .vitest-cache",
50
+ "test:coverage:fresh": "npm run test:coverage:clean && npm run test:coverage",
51
+ "test:watch": "vitest",
52
+ "format": "biome format --write src",
53
+ "format:check": "biome format src",
54
+ "lint": "biome lint src",
55
+ "lint:fix": "biome lint --write src",
56
+ "check": "biome check src",
57
+ "check:fix": "biome check --write src",
58
+ "check:deps": "madge --circular --extensions ts src",
59
+ "check:all": "npm run check && npm run lint && npm run format:check && npm run check:deps && npm run build && npm run test",
60
+ "cleanup:processes": "bash ./scripts/cleanup-test-processes.sh",
61
+ "test:safe": "npm test && npm run cleanup:processes"
62
+ },
63
+ "dependencies": {
64
+ "@google/genai": "^1.42.0",
65
+ "@modelcontextprotocol/sdk": "^1.0.0"
66
+ },
67
+ "devDependencies": {
68
+ "@biomejs/biome": "^2.4.6",
69
+ "@types/node": "^25.3.5",
70
+ "@vitest/coverage-v8": "^4.0.18",
71
+ "@vitest/ui": "^4.0.18",
72
+ "husky": "^9.1.7",
73
+ "lint-staged": "^16.3.2",
74
+ "madge": "^8.0.0",
75
+ "tsc-alias": "^1.8.16",
76
+ "tsx": "^4.21.0",
77
+ "typescript": "^5.9.3",
78
+ "vitest": "^4.0.18"
79
+ },
80
+ "engines": {
81
+ "node": ">=20"
82
+ },
83
+ "lint-staged": {
84
+ "src/**/*.{ts,tsx}": [
85
+ "biome check --write --no-errors-on-unmatched",
86
+ "biome format --write --no-errors-on-unmatched"
87
+ ]
88
+ }
89
+ }
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: image-generation
3
+ description: Enhances image generation prompts using Subject-Context-Style structure and best practices. Use this skill when generating images, creating illustrations, photos, visual assets, editing images, or crafting prompts for image generation.
4
+ ---
5
+
6
+ # Image Generation Prompt Best Practices
7
+
8
+ ## Prompt Structure
9
+
10
+ Enhance every image generation prompt around three core elements:
11
+
12
+ ### 1. SUBJECT (What)
13
+
14
+ The main focus of the image.
15
+
16
+ - Physical characteristics: textures, materials, colors, scale
17
+ - Actions, poses, expressions if applicable
18
+ - Distinctive features that define the subject
19
+
20
+ ### 2. CONTEXT (Where/When)
21
+
22
+ The environment and conditions.
23
+
24
+ - Setting, background, spatial relationships (foreground, midground, background)
25
+ - Time of day, weather, atmospheric conditions
26
+ - Mood and emotional tone of the scene
27
+
28
+ ### 3. STYLE (How)
29
+
30
+ The visual treatment.
31
+
32
+ - Artistic or photographic approach: reference specific artists, movements, or styles
33
+ - Lighting design: direction, quality, color temperature, shadows
34
+ - Camera/lens choices: specify focal length, aperture, and shooting angle when photographic
35
+
36
+ ## Core Principles
37
+
38
+ - **Preserve intent** — Enrich the user's original vision, never override it
39
+ - **Positive descriptions only** — Describe what should be present; rephrase any exclusion as an inclusion
40
+ - **Specific over vague** — "golden hour sunlight at 15° angle" beats "nice lighting"
41
+ - **Natural flow** — Weave elements into a single flowing description, not a bullet list
42
+
43
+ ## Enhancement Patterns
44
+
45
+ ### Hyper-Specific Details
46
+
47
+ Add concrete visual details where the user left gaps:
48
+
49
+ - Lighting → direction, quality, color temperature, shadow behavior
50
+ - Textures → surface materials, weathering, reflectivity
51
+ - Atmosphere → particulates, humidity, depth haze
52
+ - Scale → relative sizes, distances, proportions
53
+
54
+ ### Camera Control Terminology
55
+
56
+ When a photographic look is appropriate:
57
+
58
+ - Lens type: "shot with 85mm portrait lens", "wide-angle 24mm"
59
+ - Aperture: "shallow depth of field at f/1.8", "deep focus at f/11"
60
+ - Angle: "low angle emphasizing height", "bird's eye view"
61
+ - Motion: "motion blur on the paws", "frozen mid-action"
62
+
63
+ ### Atmospheric Enhancement
64
+
65
+ Convey mood through environmental details:
66
+
67
+ - Emotional tone: "serene", "ominous", "jubilant"
68
+ - Light quality: "dappled shadows", "harsh midday sun", "soft diffused overcast"
69
+ - Weather/air: "morning mist", "dust particles in a sunbeam"
70
+
71
+ ### Text in Images
72
+
73
+ When the image should contain readable text (signs, labels, titles, typography):
74
+
75
+ - Specify the exact text content in quotes: `"OPEN 24 HOURS" in bold sans-serif`
76
+ - Describe visual treatment: font style, weight, size relative to the scene
77
+ - Define placement and integration: "centered on the storefront awning", "hand-lettered on the chalkboard"
78
+
79
+ ## Feature Patterns
80
+
81
+ ### Character Consistency
82
+
83
+ When the same character must be recognizable across multiple images:
84
+
85
+ - Include **at least 3 recognizable visual markers** (distinctive scar, signature clothing, unique hairstyle, characteristic accessory)
86
+ - Use anchoring words: "distinctive", "signature", "always wears", "always has"
87
+ - Be specific: "round tortoiseshell glasses" not just "glasses"
88
+
89
+ ### Compositional Integration (Multi-Element Blending)
90
+
91
+ When combining multiple visual elements in one scene:
92
+
93
+ - Define spatial relationships with proportions: "foreground (40% of frame)", "midground", "background"
94
+ - Use integration language: "seamlessly blending", "harmoniously composed", "naturally integrated"
95
+ - Specify relative scale and interaction between elements
96
+
97
+ ### Real-World Accuracy
98
+
99
+ When depicting real places, cultures, or historical elements:
100
+
101
+ - Use specific terminology: "traditional Edo-period architecture", "authentic Moroccan zellige tilework"
102
+ - Include culturally accurate details
103
+ - Reference geographical or historical specifics
104
+
105
+ ### Purpose-Driven Enhancement
106
+
107
+ Tailor the prompt to the intended use:
108
+
109
+ | Purpose | Emphasis |
110
+ |---------|----------|
111
+ | Product photo | Clean background, studio lighting, commercial appeal |
112
+ | UI mockup | Flat design elements, consistent spacing, screen-appropriate |
113
+ | Presentation slide | Bold composition, clear focal point, text-friendly layout |
114
+ | Social media | Eye-catching, vibrant, crop-friendly aspect ratio |
115
+ | Book/album cover | Typography space, dramatic mood, symbolic elements |
116
+
117
+ ## Image Editing
118
+
119
+ When modifying an existing image:
120
+
121
+ - **Preserve** the original's core characteristics: color palette, lighting style, composition
122
+ - Use anchoring phrases: "maintain the existing...", "preserve the original...", "keep the same..."
123
+ - Be specific about what to change vs what to keep unchanged
124
+ - Describe modifications relative to the existing image, not from scratch
125
+
126
+ ## Example
127
+
128
+ **Input:** "A happy dog in a park"
129
+
130
+ **Enhanced:** "Golden retriever mid-leap catching a red frisbee, ears flying, tongue out in joy, in a sunlit urban park. Soft morning light filtering through oak trees creates dappled shadows on emerald grass. Background shows families on picnic blankets, slightly out of focus. Shot from low angle emphasizing the dog's athletic movement, with motion blur on the paws suggesting speed."
131
+