@renoise/plugin 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +15 -0
- package/.claude-plugin/plugin.json +23 -0
- package/README.md +53 -0
- package/hooks/check-api-key.sh +28 -0
- package/hooks/hooks.json +28 -0
- package/hooks/session-start.sh +40 -0
- package/index.mjs +1 -0
- package/openclaw.plugin.json +22 -0
- package/package.json +22 -0
- package/skills/director/SKILL.md +269 -0
- package/skills/director/references/narrative-pacing.md +257 -0
- package/skills/director/references/style-library.md +179 -0
- package/skills/file-upload/SKILL.md +79 -0
- package/skills/file-upload/scripts/upload.mjs +103 -0
- package/skills/gemini-gen/SKILL.md +236 -0
- package/skills/gemini-gen/scripts/gemini.mjs +220 -0
- package/skills/product-sheet-generate/SKILL.md +75 -0
- package/skills/renoise-gen/SKILL.md +364 -0
- package/skills/renoise-gen/references/api-endpoints.md +142 -0
- package/skills/renoise-gen/references/video-capabilities.md +524 -0
- package/skills/renoise-gen/renoise-cli.mjs +723 -0
- package/skills/scene-generate/SKILL.md +52 -0
- package/skills/short-film-editor/SKILL.md +478 -0
- package/skills/short-film-editor/examples/mystery-package-4shot.md +260 -0
- package/skills/short-film-editor/references/continuity-guide.md +170 -0
- package/skills/short-film-editor/scripts/analyze-beats.py +271 -0
- package/skills/short-film-editor/scripts/batch-generate.sh +150 -0
- package/skills/short-film-editor/scripts/split-grid.sh +70 -0
- package/skills/tiktok-content-maker/SKILL.md +140 -0
- package/skills/tiktok-content-maker/examples/dress-demo.md +86 -0
- package/skills/tiktok-content-maker/references/ecom-prompt-guide.md +266 -0
- package/skills/video-download/SKILL.md +161 -0
- package/skills/video-download/scripts/download-video.sh +91 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gemini-gen
|
|
3
|
+
description: >
|
|
4
|
+
Visual understanding and multimodal analysis via Gemini 3.1 Pro.
|
|
5
|
+
Use when you need to understand, analyze, or extract information from images or videos:
|
|
6
|
+
analyze product photos, extract video scripts/dialogue, understand video content for replication,
|
|
7
|
+
compare visual assets, OCR/text extraction from images, describe scenes for prompt writing,
|
|
8
|
+
extract style/color/composition from reference footage.
|
|
9
|
+
Do NOT use for generating images or videos — use renoise-gen instead.
|
|
10
|
+
allowed-tools: Bash, Read
|
|
11
|
+
metadata:
|
|
12
|
+
author: renoise
|
|
13
|
+
version: 0.2.0
|
|
14
|
+
category: ai-foundation
|
|
15
|
+
tags: [vision, analysis, multimodal, gemini]
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Gemini Gen — Visual Understanding & Multimodal Analysis
|
|
19
|
+
|
|
20
|
+
Gemini 3.1 Pro via Renoise gateway. Zero npm dependencies, native `fetch` only.
|
|
21
|
+
|
|
22
|
+
## When to Use
|
|
23
|
+
|
|
24
|
+
| Scenario | Example |
|
|
25
|
+
| ------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
26
|
+
| **Analyze product photos** | Extract type, color, material, selling points, brand tone from product images |
|
|
27
|
+
| **Understand video content** | "What happens in this video?", summarize scenes, identify actions and objects |
|
|
28
|
+
| **Extract scripts from video** | Watch a reference video → output timestamped dialogue, scene descriptions, camera movements |
|
|
29
|
+
| **Replicate a video style** | Analyze a reference clip → extract visual style, pacing, transitions, color grading for recreation |
|
|
30
|
+
| **Compare visual assets** | Side-by-side analysis of two product photos, before/after comparison |
|
|
31
|
+
| **OCR / text extraction** | Read text from screenshots, packaging, signage in images |
|
|
32
|
+
| **Describe scenes for prompts** | Look at a reference image → write a detailed prompt for `renoise-gen` to recreate the style |
|
|
33
|
+
| **Content review** | Check if generated output matches the creative brief |
|
|
34
|
+
|
|
35
|
+
## When NOT to Use
|
|
36
|
+
|
|
37
|
+
- **Generating images** → use `renoise-gen` with `nano-banana-2`
|
|
38
|
+
- **Generating videos** → use `renoise-gen` with `renoise-2.0`
|
|
39
|
+
- **Uploading large files** → use `file-upload` first, then pass the URL here
|
|
40
|
+
|
|
41
|
+
## Authentication
|
|
42
|
+
|
|
43
|
+
Use environment variable `RENOISE_API_KEY`. Get one at: https://www.renoise.ai
|
|
44
|
+
|
|
45
|
+
## API Endpoint
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
POST https://renoise.ai/api/public/llm/proxy/v1beta/models/{model}:generateContent?key={RENOISE_API_KEY}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Default model: `gemini-3.1-pro`
|
|
52
|
+
|
|
53
|
+
## Request Format
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"contents": [
|
|
58
|
+
{
|
|
59
|
+
"role": "user",
|
|
60
|
+
"parts": [{ "text": "your prompt here" }]
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"generationConfig": {
|
|
64
|
+
"temperature": 1.0,
|
|
65
|
+
"maxOutputTokens": 8192
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Multimodal Input (images & videos)
|
|
71
|
+
|
|
72
|
+
Gemini supports images and videos as inline base64 parts alongside text. Multiple files can be sent in the same request.
|
|
73
|
+
|
|
74
|
+
### Image Input
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"contents": [
|
|
79
|
+
{
|
|
80
|
+
"parts": [
|
|
81
|
+
{
|
|
82
|
+
"inlineData": {
|
|
83
|
+
"mimeType": "image/jpeg",
|
|
84
|
+
"data": "<base64-encoded-data>"
|
|
85
|
+
},
|
|
86
|
+
"mediaResolution": { "level": "media_resolution_high" }
|
|
87
|
+
},
|
|
88
|
+
{ "text": "Describe this image" }
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`mediaResolution` controls token allocation per image/frame:
|
|
96
|
+
|
|
97
|
+
| Level | Image Tokens | Video Frame Tokens |
|
|
98
|
+
| ----------------------------- | ------------ | ------------------ |
|
|
99
|
+
| `media_resolution_low` | 280 | 70 |
|
|
100
|
+
| `media_resolution_medium` | 560 | 140 |
|
|
101
|
+
| `media_resolution_high` | 840 | 210 |
|
|
102
|
+
| `media_resolution_ultra_high` | 1120 | 280 |
|
|
103
|
+
|
|
104
|
+
Default: `media_resolution_medium`. Use `high` or `ultra_high` for detail-critical analysis (product photos, fine text). Use `low` for bulk/batch processing.
|
|
105
|
+
|
|
106
|
+
### Video Input
|
|
107
|
+
|
|
108
|
+
Same format — just use a video MIME type. Inline base64 has a **20MB limit**. For larger videos, use the dedicated file upload skill.
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"contents": [
|
|
113
|
+
{
|
|
114
|
+
"parts": [
|
|
115
|
+
{
|
|
116
|
+
"inlineData": {
|
|
117
|
+
"mimeType": "video/mp4",
|
|
118
|
+
"data": "<base64-encoded-data>"
|
|
119
|
+
},
|
|
120
|
+
"mediaResolution": { "level": "media_resolution_low" }
|
|
121
|
+
},
|
|
122
|
+
{ "text": "Summarize what happens in this video" }
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
> **Tip**: Use `media_resolution_low` for videos to reduce token consumption — video has many frames.
|
|
130
|
+
|
|
131
|
+
### Multiple Files
|
|
132
|
+
|
|
133
|
+
Send multiple images/videos in one request by adding more `inlineData` parts:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"contents": [
|
|
138
|
+
{
|
|
139
|
+
"parts": [
|
|
140
|
+
{
|
|
141
|
+
"inlineData": { "mimeType": "image/jpeg", "data": "<base64-image-1>" }
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"inlineData": { "mimeType": "image/png", "data": "<base64-image-2>" }
|
|
145
|
+
},
|
|
146
|
+
{ "text": "Compare these two product photos" }
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Large Files (> 20MB)
|
|
154
|
+
|
|
155
|
+
Inline base64 has a **20MB limit**. For larger files, use the dedicated file upload skill to get a file URI, then reference it:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"contents": [
|
|
160
|
+
{
|
|
161
|
+
"parts": [
|
|
162
|
+
{
|
|
163
|
+
"fileData": {
|
|
164
|
+
"mimeType": "video/mp4",
|
|
165
|
+
"fileUri": "<uploaded-file-uri>"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{ "text": "Analyze this video" }
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Supported MIME Types
|
|
176
|
+
|
|
177
|
+
| Extension | MIME Type | Max Inline |
|
|
178
|
+
| ---------- | --------------- | ---------- |
|
|
179
|
+
| .jpg/.jpeg | image/jpeg | 20MB |
|
|
180
|
+
| .png | image/png | 20MB |
|
|
181
|
+
| .webp | image/webp | 20MB |
|
|
182
|
+
| .gif | image/gif | 20MB |
|
|
183
|
+
| .mp4 | video/mp4 | 20MB |
|
|
184
|
+
| .mov | video/quicktime | 20MB |
|
|
185
|
+
| .webm | video/webm | 20MB |
|
|
186
|
+
|
|
187
|
+
## Response Parsing
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
const data = await response.json();
|
|
191
|
+
const text = data.candidates[0].content.parts[0].text;
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Error Handling
|
|
195
|
+
|
|
196
|
+
- 400: Bad request (check prompt format)
|
|
197
|
+
- 403: Invalid API key
|
|
198
|
+
- 429: Rate limited (wait and retry)
|
|
199
|
+
- 500: Server error (retry with backoff)
|
|
200
|
+
|
|
201
|
+
## CLI Script
|
|
202
|
+
|
|
203
|
+
`${CLAUDE_SKILL_DIR}/scripts/gemini.mjs` — zero-dependency Node.js script, other skills can directly call it.
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Text only
|
|
207
|
+
node ${CLAUDE_SKILL_DIR}/scripts/gemini.mjs "Explain quantum computing"
|
|
208
|
+
|
|
209
|
+
# Analyze an image (high resolution for product detail)
|
|
210
|
+
node ${CLAUDE_SKILL_DIR}/scripts/gemini.mjs --file photo.jpg --resolution high "Describe this product"
|
|
211
|
+
|
|
212
|
+
# Analyze a video (low resolution to save tokens)
|
|
213
|
+
node ${CLAUDE_SKILL_DIR}/scripts/gemini.mjs --file clip.mp4 --resolution low "Summarize this clip"
|
|
214
|
+
|
|
215
|
+
# Multiple images
|
|
216
|
+
node ${CLAUDE_SKILL_DIR}/scripts/gemini.mjs --file a.jpg --file b.jpg "Compare these two"
|
|
217
|
+
|
|
218
|
+
# Uploaded file URI (from file upload skill, for files > 20MB)
|
|
219
|
+
node ${CLAUDE_SKILL_DIR}/scripts/gemini.mjs --file-uri "<uri>" --file-mime video/mp4 "Analyze this video"
|
|
220
|
+
|
|
221
|
+
# JSON output mode
|
|
222
|
+
node ${CLAUDE_SKILL_DIR}/scripts/gemini.mjs --json "Return a JSON object with name and age"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Options
|
|
226
|
+
|
|
227
|
+
| Flag | Default | Description |
|
|
228
|
+
| ---------------------- | ---------------- | ---------------------------------------------------- |
|
|
229
|
+
| `--file <path>` | — | Attach local file (repeatable) |
|
|
230
|
+
| `--file-uri <uri>` | — | Attach uploaded file by URI (requires `--file-mime`) |
|
|
231
|
+
| `--file-mime <mime>` | — | MIME type for `--file-uri` |
|
|
232
|
+
| `--resolution <level>` | `medium` | `low` / `medium` / `high` / `ultra_high` |
|
|
233
|
+
| `--model <name>` | `gemini-3.1-pro` | Model name |
|
|
234
|
+
| `--temperature <n>` | `1.0` | Temperature |
|
|
235
|
+
| `--max-tokens <n>` | `8192` | Max output tokens |
|
|
236
|
+
| `--json` | off | Request JSON response format |
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gemini API client via Renoise gateway.
|
|
5
|
+
* Zero npm dependencies — uses native fetch.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* # Text only
|
|
9
|
+
* node gemini.mjs "Explain quantum computing"
|
|
10
|
+
*
|
|
11
|
+
* # With image(s)
|
|
12
|
+
* node gemini.mjs --file photo.jpg "Describe this product"
|
|
13
|
+
* node gemini.mjs --file a.jpg --file b.jpg "Compare these two"
|
|
14
|
+
*
|
|
15
|
+
* # With video
|
|
16
|
+
* node gemini.mjs --file clip.mp4 --resolution low "Summarize this clip"
|
|
17
|
+
*
|
|
18
|
+
* # With uploaded file URI (from file upload skill)
|
|
19
|
+
* node gemini.mjs --file-uri "https://...fileUri" --file-mime video/mp4 "Analyze this video"
|
|
20
|
+
*
|
|
21
|
+
* # JSON output mode
|
|
22
|
+
* node gemini.mjs --json "Return a JSON object with name and age"
|
|
23
|
+
*
|
|
24
|
+
* Options:
|
|
25
|
+
* --file <path> Attach a local file (image/video). Repeatable.
|
|
26
|
+
* --file-uri <uri> Attach an uploaded file by URI. Requires --file-mime.
|
|
27
|
+
* --file-mime <mime> MIME type for --file-uri.
|
|
28
|
+
* --resolution <level> Media resolution: low|medium|high|ultra_high (default: medium)
|
|
29
|
+
* --model <name> Model name (default: gemini-3.1-pro)
|
|
30
|
+
* --temperature <n> Temperature (default: 1.0)
|
|
31
|
+
* --max-tokens <n> Max output tokens (default: 8192)
|
|
32
|
+
* --json Request JSON response format
|
|
33
|
+
*
|
|
34
|
+
* Environment:
|
|
35
|
+
* RENOISE_API_KEY Required. Get one at https://www.renoise.ai
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import fs from "fs/promises";
|
|
39
|
+
import path from "path";
|
|
40
|
+
|
|
41
|
+
// --- Auth ---
|
|
42
|
+
const RENOISE_API_KEY = process.env.RENOISE_API_KEY;
|
|
43
|
+
if (!RENOISE_API_KEY) {
|
|
44
|
+
console.error(
|
|
45
|
+
"RENOISE_API_KEY not set. Get one at: https://www.renoise.ai"
|
|
46
|
+
);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// --- MIME detection ---
|
|
51
|
+
const MIME_MAP = {
|
|
52
|
+
".jpg": "image/jpeg",
|
|
53
|
+
".jpeg": "image/jpeg",
|
|
54
|
+
".png": "image/png",
|
|
55
|
+
".webp": "image/webp",
|
|
56
|
+
".gif": "image/gif",
|
|
57
|
+
".mp4": "video/mp4",
|
|
58
|
+
".mov": "video/quicktime",
|
|
59
|
+
".webm": "video/webm",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function getMimeType(filePath) {
|
|
63
|
+
return (
|
|
64
|
+
MIME_MAP[path.extname(filePath).toLowerCase()] ?? "application/octet-stream"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// --- Resolution mapping ---
|
|
69
|
+
const RESOLUTION_MAP = {
|
|
70
|
+
low: "media_resolution_low",
|
|
71
|
+
medium: "media_resolution_medium",
|
|
72
|
+
high: "media_resolution_high",
|
|
73
|
+
ultra_high: "media_resolution_ultra_high",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// --- Parse args ---
|
|
77
|
+
function parseArgs(argv) {
|
|
78
|
+
const files = [];
|
|
79
|
+
let fileUri = null;
|
|
80
|
+
let fileMime = null;
|
|
81
|
+
let resolution = "medium";
|
|
82
|
+
let model = "gemini-3.1-pro";
|
|
83
|
+
let temperature = 1.0;
|
|
84
|
+
let maxTokens = 8192;
|
|
85
|
+
let json = false;
|
|
86
|
+
const textParts = [];
|
|
87
|
+
|
|
88
|
+
for (let i = 0; i < argv.length; i++) {
|
|
89
|
+
switch (argv[i]) {
|
|
90
|
+
case "--file":
|
|
91
|
+
files.push(argv[++i]);
|
|
92
|
+
break;
|
|
93
|
+
case "--file-uri":
|
|
94
|
+
fileUri = argv[++i];
|
|
95
|
+
break;
|
|
96
|
+
case "--file-mime":
|
|
97
|
+
fileMime = argv[++i];
|
|
98
|
+
break;
|
|
99
|
+
case "--resolution":
|
|
100
|
+
resolution = argv[++i];
|
|
101
|
+
break;
|
|
102
|
+
case "--model":
|
|
103
|
+
model = argv[++i];
|
|
104
|
+
break;
|
|
105
|
+
case "--temperature":
|
|
106
|
+
temperature = parseFloat(argv[++i]);
|
|
107
|
+
break;
|
|
108
|
+
case "--max-tokens":
|
|
109
|
+
maxTokens = parseInt(argv[++i], 10);
|
|
110
|
+
break;
|
|
111
|
+
case "--json":
|
|
112
|
+
json = true;
|
|
113
|
+
break;
|
|
114
|
+
default:
|
|
115
|
+
textParts.push(argv[i]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
files,
|
|
121
|
+
fileUri,
|
|
122
|
+
fileMime,
|
|
123
|
+
resolution,
|
|
124
|
+
model,
|
|
125
|
+
temperature,
|
|
126
|
+
maxTokens,
|
|
127
|
+
json,
|
|
128
|
+
prompt: textParts.join(" "),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// --- Build parts ---
|
|
133
|
+
async function buildParts(opts) {
|
|
134
|
+
const parts = [];
|
|
135
|
+
const resLevel = RESOLUTION_MAP[opts.resolution] ?? RESOLUTION_MAP.medium;
|
|
136
|
+
|
|
137
|
+
// Local files → inline base64
|
|
138
|
+
for (const filePath of opts.files) {
|
|
139
|
+
const data = await fs.readFile(filePath);
|
|
140
|
+
parts.push({
|
|
141
|
+
inlineData: {
|
|
142
|
+
mimeType: getMimeType(filePath),
|
|
143
|
+
data: data.toString("base64"),
|
|
144
|
+
},
|
|
145
|
+
mediaResolution: { level: resLevel },
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Uploaded file URI
|
|
150
|
+
if (opts.fileUri) {
|
|
151
|
+
parts.push({
|
|
152
|
+
fileData: {
|
|
153
|
+
mimeType: opts.fileMime ?? "application/octet-stream",
|
|
154
|
+
fileUri: opts.fileUri,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Text prompt (always last)
|
|
160
|
+
if (opts.prompt) {
|
|
161
|
+
parts.push({ text: opts.prompt });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return parts;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// --- Main ---
|
|
168
|
+
async function main() {
|
|
169
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
170
|
+
|
|
171
|
+
if (!opts.prompt && opts.files.length === 0 && !opts.fileUri) {
|
|
172
|
+
console.error(
|
|
173
|
+
"Usage: node gemini.mjs [--file <path>] [--resolution low|medium|high|ultra_high] <prompt>"
|
|
174
|
+
);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const endpoint = `https://renoise.ai/api/public/llm/proxy/v1beta/models/${opts.model}:generateContent?key=${RENOISE_API_KEY}`;
|
|
179
|
+
|
|
180
|
+
const parts = await buildParts(opts);
|
|
181
|
+
|
|
182
|
+
const body = {
|
|
183
|
+
contents: [{ role: "user", parts }],
|
|
184
|
+
generationConfig: {
|
|
185
|
+
temperature: opts.temperature,
|
|
186
|
+
maxOutputTokens: opts.maxTokens,
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
if (opts.json) {
|
|
191
|
+
body.generationConfig.responseMimeType = "application/json";
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const res = await fetch(endpoint, {
|
|
195
|
+
method: "POST",
|
|
196
|
+
headers: { "Content-Type": "application/json" },
|
|
197
|
+
body: JSON.stringify(body),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
if (!res.ok) {
|
|
201
|
+
const errText = await res.text();
|
|
202
|
+
console.error(`Gemini API error ${res.status}: ${errText}`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const data = await res.json();
|
|
207
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
208
|
+
|
|
209
|
+
if (!text) {
|
|
210
|
+
console.error("No text in response:", JSON.stringify(data, null, 2));
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
console.log(text);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
main().catch((err) => {
|
|
218
|
+
console.error("ERROR:", err.message);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: product-sheet-generate
|
|
3
|
+
description: >
|
|
4
|
+
Generates multi-angle Product Design Sheet from product photos using Renoise
|
|
5
|
+
nano-banana-2. Shows front/back/side views, color palette, materials, and
|
|
6
|
+
construction details. Use when user says "product design sheet", "product
|
|
7
|
+
reference image", "multi-angle product view", or needs a visual reference
|
|
8
|
+
for video production. Do NOT use for scene backgrounds or video generation.
|
|
9
|
+
allowed-tools: Bash, Read
|
|
10
|
+
metadata:
|
|
11
|
+
author: renoise
|
|
12
|
+
version: 0.2.0
|
|
13
|
+
category: video-production
|
|
14
|
+
tags: [product, design, renoise]
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Product Design Sheet Generation
|
|
18
|
+
|
|
19
|
+
Generate a comprehensive Product Design Sheet image from product photos using Renoise `nano-banana-2` model.
|
|
20
|
+
|
|
21
|
+
## Arguments
|
|
22
|
+
|
|
23
|
+
- First argument — Product images directory or single image path (required)
|
|
24
|
+
- Second argument — Output directory (required, e.g. `output/foam-roller-20260313-1420/analysis`)
|
|
25
|
+
|
|
26
|
+
## What is a Product Design Sheet?
|
|
27
|
+
|
|
28
|
+
A single image containing:
|
|
29
|
+
- Multiple angle views (front, back, side, three-quarter, bottom)
|
|
30
|
+
- Color palette with Pantone or hex references
|
|
31
|
+
- Material and texture callouts
|
|
32
|
+
- Construction details and hardware close-ups
|
|
33
|
+
- Proportions and measurements
|
|
34
|
+
- Interior views (if applicable)
|
|
35
|
+
|
|
36
|
+
## Instructions
|
|
37
|
+
|
|
38
|
+
1. List images in the input path to confirm they exist.
|
|
39
|
+
|
|
40
|
+
2. Upload each product image as a material:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
node ${CLAUDE_SKILL_DIR}/../renoise-gen/renoise-cli.mjs material upload "<image_path>"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Note the material ID from each upload output (e.g. `#42`).
|
|
47
|
+
|
|
48
|
+
3. Write an English prompt for the design sheet. Example:
|
|
49
|
+
|
|
50
|
+
> Based on the provided product reference photos, generate a professional Product Design Sheet on a single clean white background. Include: multiple angle views (front, back, side, three-quarter, top), color palette swatches, material and texture close-ups, construction detail callouts, and relative proportions. Layout: clean organized grid. Photorealistic rendering. No cartoons or illustrations.
|
|
51
|
+
|
|
52
|
+
Add `Do NOT include any text, labels, titles, annotations, or typography.` if user wants no-text version.
|
|
53
|
+
|
|
54
|
+
4. Generate the design sheet, referencing the uploaded materials:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
node ${CLAUDE_SKILL_DIR}/../renoise-gen/renoise-cli.mjs task generate \
|
|
58
|
+
--model nano-banana-2 \
|
|
59
|
+
--prompt "<english_prompt>" \
|
|
60
|
+
--materials "<id1>:ref_image,<id2>:image1,<id3>:image2" \
|
|
61
|
+
--resolution 2k \
|
|
62
|
+
--ratio 1:1
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Assign material roles: first image as `ref_image`, additional images as `image1`, `image2`, etc.
|
|
66
|
+
|
|
67
|
+
5. The command will output an `imageUrl` when complete. Download the image:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
curl -sL "<imageUrl>" -o "<output_dir>/product_design_sheet.png"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
6. Verify the output image was created and print file size.
|
|
74
|
+
|
|
75
|
+
7. Show the generated image to the user for approval. If not satisfactory, adjust the prompt and regenerate.
|