@renoise/video-maker 0.1.3 → 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.
@@ -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
+ });
@@ -13,6 +13,8 @@ metadata:
13
13
 
14
14
  Generate AI videos and images through the Renoise platform.
15
15
 
16
+ > **IMPORTANT**: The Renoise website is **https://www.renoise.ai** — NOT renoise.com. Always use `renoise.ai` when referencing the platform URL.
17
+
16
18
  ## Supported Models
17
19
 
18
20
  | Model | Type | Description |
@@ -96,7 +98,7 @@ See `${CLAUDE_SKILL_DIR}/references/video-capabilities.md` for details.
96
98
 
97
99
  CLI path: `${CLAUDE_SKILL_DIR}/renoise-cli.mjs` (Node.js 18+)
98
100
 
99
- API Key and base URL are configured via environment variables (`RENOISE_API_KEY`, `RENOISE_BASE_URL`).
101
+ API Key and base URL are configured via environment variables (`RENOISE_API_KEY`, `RENOISE_BASE_URL`). Get your API key at https://www.renoise.ai (NOT renoise.com).
100
102
 
101
103
  ## CLI Commands
102
104
 
@@ -2,50 +2,51 @@
2
2
 
3
3
  ## API Endpoints
4
4
 
5
- Base URL: `https://staging--ujgsvru36x4korjj10nq.edgespark.app`
5
+ Base URL: `https://renoise.ai`
6
6
  API Prefix: `/api/public/v1`
7
7
 
8
8
  All endpoints require `X-API-Key: <api_key>` header.
9
9
 
10
10
  ### Credits
11
11
 
12
- | Method | Path | Description |
13
- |--------|------|-------------|
14
- | GET | `/api/public/v1/me` | User info + credit balance |
15
- | GET | `/api/public/v1/credit/estimate?model=X&duration=Y&hasVideoRef=0` | Cost estimate |
16
- | GET | `/api/public/v1/credit/history?limit=50&offset=0` | Credit transactions |
12
+ | Method | Path | Description |
13
+ | ------ | ----------------------------------------------------------------- | -------------------------- |
14
+ | GET | `/api/public/v1/me` | User info + credit balance |
15
+ | GET | `/api/public/v1/credit/estimate?model=X&duration=Y&hasVideoRef=0` | Cost estimate |
16
+ | GET | `/api/public/v1/credit/history?limit=50&offset=0` | Credit transactions |
17
17
 
18
18
  ### Tasks
19
19
 
20
- | Method | Path | Description |
21
- |--------|------|-------------|
22
- | POST | `/api/public/v1/tasks` | Create task |
23
- | GET | `/api/public/v1/tasks?status=X&tag=Y&limit=50&offset=0` | List tasks |
24
- | GET | `/api/public/v1/tasks/:id` | Task detail |
25
- | GET | `/api/public/v1/tasks/:id/result` | Task result (video/image/cover URLs) |
26
- | POST | `/api/public/v1/tasks/:id/cancel` | Cancel pending task |
27
- | PATCH | `/api/public/v1/tasks/:id/tags` | Update tags |
28
- | GET | `/api/public/v1/tags` | List all tags |
20
+ | Method | Path | Description |
21
+ | ------ | ------------------------------------------------------- | ------------------------------------ |
22
+ | POST | `/api/public/v1/tasks` | Create task |
23
+ | GET | `/api/public/v1/tasks?status=X&tag=Y&limit=50&offset=0` | List tasks |
24
+ | GET | `/api/public/v1/tasks/:id` | Task detail |
25
+ | GET | `/api/public/v1/tasks/:id/result` | Task result (video/image/cover URLs) |
26
+ | POST | `/api/public/v1/tasks/:id/cancel` | Cancel pending task |
27
+ | PATCH | `/api/public/v1/tasks/:id/tags` | Update tags |
28
+ | GET | `/api/public/v1/tags` | List all tags |
29
29
 
30
30
  ### Materials
31
31
 
32
- | Method | Path | Description |
33
- |--------|------|-------------|
34
- | POST | `/api/public/v1/materials/upload` | Upload material (multipart) |
35
- | GET | `/api/public/v1/materials?type=X&search=Y` | List materials with download URLs |
32
+ | Method | Path | Description |
33
+ | ------ | ------------------------------------------ | --------------------------------- |
34
+ | POST | `/api/public/v1/materials/upload` | Upload material (multipart) |
35
+ | GET | `/api/public/v1/materials?type=X&search=Y` | List materials with download URLs |
36
36
 
37
37
  ### Characters
38
38
 
39
- | Method | Path | Description |
40
- |--------|------|-------------|
41
- | GET | `/api/public/v1/characters?category=X&usage_group=Y&search=Z&page=1&page_size=20` | List characters |
42
- | GET | `/api/public/v1/characters/:id` | Character detail |
39
+ | Method | Path | Description |
40
+ | ------ | --------------------------------------------------------------------------------- | ---------------- |
41
+ | GET | `/api/public/v1/characters?category=X&usage_group=Y&search=Z&page=1&page_size=20` | List characters |
42
+ | GET | `/api/public/v1/characters/:id` | Character detail |
43
43
 
44
44
  ## Request/Response Formats
45
45
 
46
46
  ### POST /api/public/v1/tasks
47
47
 
48
48
  Request:
49
+
49
50
  ```json
50
51
  {
51
52
  "prompt": "string (required)",
@@ -62,6 +63,7 @@ Request:
62
63
  ```
63
64
 
64
65
  Response (201):
66
+
65
67
  ```json
66
68
  {
67
69
  "task": {
@@ -76,6 +78,7 @@ Response (201):
76
78
  ```
77
79
 
78
80
  Error (402 — insufficient credits):
81
+
79
82
  ```json
80
83
  {
81
84
  "error": "Insufficient credits",
@@ -87,6 +90,7 @@ Error (402 — insufficient credits):
87
90
  ### GET /api/public/v1/tasks/:id/result
88
91
 
89
92
  Response:
93
+
90
94
  ```json
91
95
  {
92
96
  "taskId": 1,
@@ -103,16 +107,16 @@ Response:
103
107
 
104
108
  ## Task Statuses
105
109
 
106
- | Status | Description |
107
- |--------|-------------|
108
- | `pending` | Waiting for assignment |
109
- | `assigning` | Being assigned to account |
110
- | `assigned` | Assigned, waiting to start |
111
- | `queued` | Queued on provider |
112
- | `running` | Generating |
113
- | `completed` | Done — result available |
114
- | `failed` | Failed — check error field |
115
- | `cancelled` | User cancelled |
110
+ | Status | Description |
111
+ | ----------- | -------------------------- |
112
+ | `pending` | Waiting for assignment |
113
+ | `assigning` | Being assigned to account |
114
+ | `assigned` | Assigned, waiting to start |
115
+ | `queued` | Queued on provider |
116
+ | `running` | Generating |
117
+ | `completed` | Done — result available |
118
+ | `failed` | Failed — check error field |
119
+ | `cancelled` | User cancelled |
116
120
 
117
121
  ## Models
118
122