@conceptcraft/mindframes 0.1.12 → 0.1.14
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/dist/index.js +768 -223
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
|
-
import { Command as
|
|
5
|
+
import { Command as Command21 } from "commander";
|
|
6
6
|
import chalk13 from "chalk";
|
|
7
7
|
|
|
8
8
|
// src/lib/brand.ts
|
|
@@ -1087,6 +1087,12 @@ async function searchImages(searchRequest) {
|
|
|
1087
1087
|
body: searchRequest
|
|
1088
1088
|
});
|
|
1089
1089
|
}
|
|
1090
|
+
async function generateImage(generateRequest) {
|
|
1091
|
+
return request("/api/cli/images/generate", {
|
|
1092
|
+
method: "POST",
|
|
1093
|
+
body: generateRequest
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1090
1096
|
async function searchVideos(searchRequest) {
|
|
1091
1097
|
return request("/api/cli/videos/search", {
|
|
1092
1098
|
method: "POST",
|
|
@@ -1103,6 +1109,12 @@ async function pollForCompletion(checkFn, maxAttempts = 60, intervalMs = 2e3) {
|
|
|
1103
1109
|
}
|
|
1104
1110
|
throw new ApiError("Operation timed out", 408, 1);
|
|
1105
1111
|
}
|
|
1112
|
+
async function scrapeUrl(url) {
|
|
1113
|
+
return request("/api/cli/scrape", {
|
|
1114
|
+
method: "POST",
|
|
1115
|
+
body: { url }
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1106
1118
|
|
|
1107
1119
|
// src/lib/feature-cache.ts
|
|
1108
1120
|
var cache = new Conf2({
|
|
@@ -1158,7 +1170,7 @@ function getCachePath() {
|
|
|
1158
1170
|
}
|
|
1159
1171
|
|
|
1160
1172
|
// src/commands/login.ts
|
|
1161
|
-
var CLI_CLIENT_NAME =
|
|
1173
|
+
var CLI_CLIENT_NAME = `${brand.displayName} CLI`;
|
|
1162
1174
|
var CALLBACK_PORT_START = 8765;
|
|
1163
1175
|
var CALLBACK_PORT_END = 8775;
|
|
1164
1176
|
function generateCodeVerifier() {
|
|
@@ -1408,11 +1420,11 @@ async function runLoginFlow(options) {
|
|
|
1408
1420
|
throw err;
|
|
1409
1421
|
}
|
|
1410
1422
|
}
|
|
1411
|
-
var loginCommand = new Command("login").description(
|
|
1423
|
+
var loginCommand = new Command("login").description(`Authenticate with ${brand.displayName} (opens browser)`).option("--no-browser", "Print URL instead of opening browser").action(async (options) => {
|
|
1412
1424
|
console.log();
|
|
1413
1425
|
if (hasOAuthTokens()) {
|
|
1414
1426
|
warn("You are already logged in.");
|
|
1415
|
-
info(
|
|
1427
|
+
info(`Run '${brand.commands[0]} logout' to log out first, or continue to re-authenticate.`);
|
|
1416
1428
|
console.log();
|
|
1417
1429
|
}
|
|
1418
1430
|
try {
|
|
@@ -1470,7 +1482,7 @@ import ora2 from "ora";
|
|
|
1470
1482
|
var configCommand = new Command3("config").description("Manage CLI configuration").addCommand(
|
|
1471
1483
|
new Command3("init").description("Initialize configuration interactively").action(async () => {
|
|
1472
1484
|
console.log();
|
|
1473
|
-
console.log(chalk4.bold(
|
|
1485
|
+
console.log(chalk4.bold(`${brand.displayName} CLI Configuration`));
|
|
1474
1486
|
console.log(chalk4.gray("\u2500".repeat(35)));
|
|
1475
1487
|
console.log();
|
|
1476
1488
|
try {
|
|
@@ -1489,7 +1501,7 @@ var configCommand = new Command3("config").description("Manage CLI configuration
|
|
|
1489
1501
|
});
|
|
1490
1502
|
setApiKey(apiKey.trim());
|
|
1491
1503
|
const useCustomUrl = await confirm2({
|
|
1492
|
-
message:
|
|
1504
|
+
message: `Use a custom API URL? (default: ${brand.apiUrl.replace("https://", "")})`,
|
|
1493
1505
|
default: false
|
|
1494
1506
|
});
|
|
1495
1507
|
if (useCustomUrl) {
|
|
@@ -1544,7 +1556,7 @@ var configCommand = new Command3("config").description("Manage CLI configuration
|
|
|
1544
1556
|
warn(
|
|
1545
1557
|
`Could not verify API key: ${apiErr instanceof Error ? apiErr.message : String(apiErr)}`
|
|
1546
1558
|
);
|
|
1547
|
-
warn(
|
|
1559
|
+
warn(`You may need to set the team ID manually: ${brand.commands[0]} config set team-id <id>`);
|
|
1548
1560
|
}
|
|
1549
1561
|
console.log();
|
|
1550
1562
|
success("Configuration saved!");
|
|
@@ -1648,7 +1660,7 @@ var configCommand = new Command3("config").description("Manage CLI configuration
|
|
|
1648
1660
|
try {
|
|
1649
1661
|
await fetchAndCache();
|
|
1650
1662
|
spinner.succeed("Feature flags refreshed");
|
|
1651
|
-
info(
|
|
1663
|
+
info(`Run '${brand.commands[0]} --help' to see updated commands`);
|
|
1652
1664
|
} catch (err) {
|
|
1653
1665
|
spinner.fail("Failed to refresh");
|
|
1654
1666
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -1996,29 +2008,29 @@ ${chalk6.bold("Recommended Usage:")}
|
|
|
1996
2008
|
|
|
1997
2009
|
${chalk6.bold("Examples:")}
|
|
1998
2010
|
${chalk6.gray("# Content from PDF + style from image reference")}
|
|
1999
|
-
$
|
|
2011
|
+
$ ${brand.commands[0]} create "Quarterly Report" \\
|
|
2000
2012
|
--file ./report.pdf \\
|
|
2001
2013
|
--reference-url https://example.com/style-template.png \\
|
|
2002
2014
|
-n 12 -m best --audience "Executive team"
|
|
2003
2015
|
|
|
2004
2016
|
${chalk6.gray("# Upload content files (PDF, PPTX, DOCX)")}
|
|
2005
|
-
$
|
|
2017
|
+
$ ${brand.commands[0]} create "Product Demo" \\
|
|
2006
2018
|
--file ./existing-deck.pptx --file ./specs.pdf \\
|
|
2007
2019
|
--goal persuade --audience "Enterprise buyers"
|
|
2008
2020
|
|
|
2009
2021
|
${chalk6.gray("# Inline context with custom styling")}
|
|
2010
|
-
$
|
|
2022
|
+
$ ${brand.commands[0]} create "Q4 Business Review" \\
|
|
2011
2023
|
-n 12 -m best --goal inform \\
|
|
2012
2024
|
--context "Revenue: $50M (+25% YoY), EBITDA: $8M" \\
|
|
2013
2025
|
--reference-url https://example.com/brand-style.jpg
|
|
2014
2026
|
|
|
2015
2027
|
${chalk6.gray("# Research presentation from URLs")}
|
|
2016
|
-
$
|
|
2028
|
+
$ ${brand.commands[0]} create "AI Industry Trends" \\
|
|
2017
2029
|
-n 10 -m best -t educational \\
|
|
2018
2030
|
--sources https://example.com/ai-report.pdf
|
|
2019
2031
|
|
|
2020
2032
|
${chalk6.gray("# Pipe content from another command")}
|
|
2021
|
-
$ cat meeting-notes.md |
|
|
2033
|
+
$ cat meeting-notes.md | ${brand.commands[0]} create "Meeting Summary" \\
|
|
2022
2034
|
-n 6 -m balanced --goal inform
|
|
2023
2035
|
|
|
2024
2036
|
${chalk6.bold("Content Options (what to include in slides):")}
|
|
@@ -2047,7 +2059,7 @@ ${chalk6.bold("Theme Options:")}
|
|
|
2047
2059
|
--decorations <style> Background style (none, waves-bottom-left, waves-top-right, blob-corners, minimal)
|
|
2048
2060
|
|
|
2049
2061
|
${chalk6.gray("Example: Apply corporate colors")}
|
|
2050
|
-
$
|
|
2062
|
+
$ ${brand.commands[0]} create "Brand Deck" \\
|
|
2051
2063
|
--theme blue --primary-color "#1E40AF" --decorations waves-bottom-left
|
|
2052
2064
|
|
|
2053
2065
|
${chalk6.bold("Mode Reference:")}
|
|
@@ -2282,11 +2294,11 @@ Uploading ${options.file.length} file(s)...`));
|
|
|
2282
2294
|
console.log(chalk6.gray(" -c, --context <text> Direct text context"));
|
|
2283
2295
|
console.log(chalk6.gray(" --context-file <path> Read from a file"));
|
|
2284
2296
|
console.log(chalk6.gray(" --sources <urls...> URLs to scrape"));
|
|
2285
|
-
console.log(chalk6.gray(
|
|
2297
|
+
console.log(chalk6.gray(` cat file | ${brand.commands[0]} Pipe content`));
|
|
2286
2298
|
console.log();
|
|
2287
2299
|
console.log(chalk6.gray("Example:"));
|
|
2288
|
-
console.log(chalk6.cyan(
|
|
2289
|
-
console.log(chalk6.cyan(
|
|
2300
|
+
console.log(chalk6.cyan(` ${brand.commands[0]} create "Q4 Report" --file ./report.pdf`));
|
|
2301
|
+
console.log(chalk6.cyan(` ${brand.commands[0]} create "Q4 Report" --context "Revenue: $10M, Growth: 25%"`));
|
|
2290
2302
|
process.exit(6);
|
|
2291
2303
|
}
|
|
2292
2304
|
try {
|
|
@@ -2427,7 +2439,7 @@ var listCommand = new Command5("list").description("List presentations").option(
|
|
|
2427
2439
|
const teamId = options.teamId ?? getDefaultTeamId();
|
|
2428
2440
|
if (!teamId) {
|
|
2429
2441
|
error(
|
|
2430
|
-
"Team ID required. Set a default with '
|
|
2442
|
+
"`Team ID required. Set a default with '${brand.commands[0]} config set team-id <id>' or use --team-id`"
|
|
2431
2443
|
);
|
|
2432
2444
|
process.exit(6);
|
|
2433
2445
|
}
|
|
@@ -2698,7 +2710,7 @@ var brandingCommand = new Command10("branding").description("Manage brand profil
|
|
|
2698
2710
|
console.log();
|
|
2699
2711
|
console.log(
|
|
2700
2712
|
chalk8.gray(
|
|
2701
|
-
"Create one with:
|
|
2713
|
+
"`Create one with: ${brand.commands[0]} branding extract <url>`"
|
|
2702
2714
|
)
|
|
2703
2715
|
);
|
|
2704
2716
|
}
|
|
@@ -2831,7 +2843,7 @@ var brandingCommand = new Command10("branding").description("Manage brand profil
|
|
|
2831
2843
|
console.log(` Confidence: ${Math.round(brand2.confidence * 100)}%`);
|
|
2832
2844
|
console.log();
|
|
2833
2845
|
}
|
|
2834
|
-
info(`Create a presentation with this brand:
|
|
2846
|
+
info(`Create a presentation with this brand: ${brand2.commands[0]} create "Your Topic" -b ${result.id}`);
|
|
2835
2847
|
console.log();
|
|
2836
2848
|
} catch (err) {
|
|
2837
2849
|
spinner.fail("Extraction failed");
|
|
@@ -2994,7 +3006,7 @@ var ideasCommand = new Command12("ideas").description("Generate presentation top
|
|
|
2994
3006
|
console.log("For now, try these approaches:");
|
|
2995
3007
|
console.log(
|
|
2996
3008
|
chalk10.gray(
|
|
2997
|
-
" 1. Visit the
|
|
3009
|
+
"` 1. Visit the ${brand.displayName} dashboard and use the idea generator`"
|
|
2998
3010
|
)
|
|
2999
3011
|
);
|
|
3000
3012
|
console.log(
|
|
@@ -3090,6 +3102,7 @@ A comprehensive CLI for AI-powered content creation. Generate presentations, vid
|
|
|
3090
3102
|
| Search images | \`${cmd2} image search -q "mountain landscape"\` |
|
|
3091
3103
|
| Search videos | \`${cmd2} video search "ocean waves"\` |
|
|
3092
3104
|
| Mix audio tracks | \`${cmd2} mix create --video v.mp4 --music m.mp3\` |
|
|
3105
|
+
| Scrape URL content | \`${cmd2} scrape https://example.com\` |
|
|
3093
3106
|
|
|
3094
3107
|
---
|
|
3095
3108
|
|
|
@@ -3146,7 +3159,7 @@ ${cmd2} create "Pitch Deck" \\
|
|
|
3146
3159
|
- \`--mode <instant|ultrafast|fast|balanced|best>\` - Quality/speed tradeoff
|
|
3147
3160
|
- \`--tone <creative|professional|educational|formal|casual>\`
|
|
3148
3161
|
- \`--file <paths...>\` - Extract content from files
|
|
3149
|
-
- \`--sources <urls...>\` - Scrape URLs for context
|
|
3162
|
+
- \`--sources <urls...>\` - Scrape URLs for context (auto-routes YouTube, Twitter/X)
|
|
3150
3163
|
- \`--brand <id|url>\` - Apply branding
|
|
3151
3164
|
- \`--open\` - Open in browser when done
|
|
3152
3165
|
|
|
@@ -3187,7 +3200,7 @@ cat <<'EOF' | ${cmd2} video create --output ./public
|
|
|
3187
3200
|
"imageQuery": "call to action button"
|
|
3188
3201
|
}
|
|
3189
3202
|
],
|
|
3190
|
-
"
|
|
3203
|
+
"voiceId": "21m00Tcm4TlvDq8ikWAM",
|
|
3191
3204
|
"voiceSettings": {
|
|
3192
3205
|
"speed": 0.95,
|
|
3193
3206
|
"stability": 0.4,
|
|
@@ -3333,7 +3346,35 @@ Music automatically loops to match video duration.
|
|
|
3333
3346
|
|
|
3334
3347
|
---
|
|
3335
3348
|
|
|
3336
|
-
## 8.
|
|
3349
|
+
## 8. URL Scraping
|
|
3350
|
+
|
|
3351
|
+
Extract content from URLs for analysis, context gathering, or research.
|
|
3352
|
+
|
|
3353
|
+
\`\`\`bash
|
|
3354
|
+
# Basic scrape
|
|
3355
|
+
${cmd2} scrape https://example.com
|
|
3356
|
+
|
|
3357
|
+
# Save to file
|
|
3358
|
+
${cmd2} scrape https://company.com/about -o about.md
|
|
3359
|
+
|
|
3360
|
+
# JSON output (for programmatic use)
|
|
3361
|
+
${cmd2} scrape https://docs.example.com --format json
|
|
3362
|
+
|
|
3363
|
+
# Quiet mode (content only)
|
|
3364
|
+
${cmd2} scrape https://blog.example.com --format quiet > content.txt
|
|
3365
|
+
\`\`\`
|
|
3366
|
+
|
|
3367
|
+
**Use cases:**
|
|
3368
|
+
- Gather context for presentation creation
|
|
3369
|
+
- Research competitor features
|
|
3370
|
+
- Extract documentation for analysis
|
|
3371
|
+
- Feed content into other workflows
|
|
3372
|
+
|
|
3373
|
+
**Output includes:** title, description, full content (markdown), token count, cost
|
|
3374
|
+
|
|
3375
|
+
---
|
|
3376
|
+
|
|
3377
|
+
## 9. Branding
|
|
3337
3378
|
|
|
3338
3379
|
Manage brand profiles for consistent styling.
|
|
3339
3380
|
|
|
@@ -3356,7 +3397,7 @@ ${cmd2} create "Topic" --brand my-company
|
|
|
3356
3397
|
|
|
3357
3398
|
---
|
|
3358
3399
|
|
|
3359
|
-
##
|
|
3400
|
+
## 10. Configuration
|
|
3360
3401
|
|
|
3361
3402
|
\`\`\`bash
|
|
3362
3403
|
# Interactive setup
|
|
@@ -3483,231 +3524,636 @@ ${cmd2} --version # Version info
|
|
|
3483
3524
|
`;
|
|
3484
3525
|
}
|
|
3485
3526
|
|
|
3486
|
-
// src/commands/skill/
|
|
3487
|
-
|
|
3527
|
+
// src/commands/skill/generate-video-skill.ts
|
|
3528
|
+
function generateVideoSkillContent(context) {
|
|
3529
|
+
const { name, cmd: cmd2 } = context;
|
|
3530
|
+
return `---
|
|
3531
|
+
name: ${name}-video
|
|
3532
|
+
description: Orchestrates video asset assembly for marketing videos, product demos, explainers, and promo content. Analyzes projects to extract branding (logos, colors, fonts), identifies reusable UI components, generates voiceovers and music via CLI, searches stock media, and produces a video-manifest.json. Use when user says "create a video", "make a promo", "product demo", "explainer video", "marketing video", "gather video assets", "video for my project", or "TikTok/Reels content".
|
|
3533
|
+
---
|
|
3488
3534
|
|
|
3489
|
-
|
|
3490
|
-
- Expressive faces (emotion, not neutral) boost CTR 20-30%
|
|
3491
|
-
- High contrast, bold colors (yellow, orange stand out)
|
|
3492
|
-
- Simple: 3 main elements max (face + text + 1 visual)
|
|
3493
|
-
- Mobile-first: readable at 320px width (70% of views)
|
|
3494
|
-
- Minimal text: 3-5 words, bold legible fonts (60-80px)
|
|
3495
|
-
- Rule of thirds composition
|
|
3535
|
+
# Video Asset Assembler (Phase 1)
|
|
3496
3536
|
|
|
3497
|
-
|
|
3537
|
+
You are an expert video producer who prepares all assets needed for Remotion video rendering. Your job is to analyze the project, gather resources, generate audio, and create a complete manifest\u2014NOT to render the final video.
|
|
3498
3538
|
|
|
3499
|
-
|
|
3500
|
-
`;
|
|
3501
|
-
var MOTION_DESIGN_GUIDELINES = `# Motion Design Principles
|
|
3539
|
+
## When to Use This Skill
|
|
3502
3540
|
|
|
3503
|
-
**
|
|
3541
|
+
\u2705 **USE for:**
|
|
3542
|
+
- Marketing videos, product demos, launch videos
|
|
3543
|
+
- News/trending topic videos
|
|
3544
|
+
- Explainer videos from any source
|
|
3545
|
+
- Social content (TikTok, Reels, YouTube Shorts)
|
|
3546
|
+
- Any video that needs voiceover + visuals + music
|
|
3504
3547
|
|
|
3505
|
-
|
|
3548
|
+
\u274C **DO NOT use for:**
|
|
3549
|
+
- Editing existing video files (use ffmpeg directly)
|
|
3550
|
+
- Live streaming setup
|
|
3551
|
+
- Video format conversion
|
|
3552
|
+
- Simple image slideshows without voiceover
|
|
3506
3553
|
|
|
3507
|
-
|
|
3508
|
-
- Theme object: colors (primary, accent, background, text), fonts, corner radiuses in config
|
|
3509
|
-
- Scene object: define by duration in frames and content type, not timecodes
|
|
3510
|
-
- Avoid hardcoding: colors, text, data values can be passed via props or config file
|
|
3554
|
+
## Critical Rules
|
|
3511
3555
|
|
|
3512
|
-
|
|
3556
|
+
1. **NEVER hallucinate file paths.** Before referencing any file, VERIFY it exists with \`ls\` or \`find\`.
|
|
3557
|
+
2. **NEVER skip the discovery phase.** Always analyze source material before scripting.
|
|
3558
|
+
3. **ALWAYS use the CLI** for audio generation\u2014don't simulate or skip it.
|
|
3559
|
+
4. **ALWAYS produce a valid video-manifest.json** at the end.
|
|
3560
|
+
5. **ALWAYS ask clarifying questions** if video type, duration, or tone is unclear.
|
|
3513
3561
|
|
|
3514
|
-
|
|
3515
|
-
- UI cards, bubbles, logos "pop" with bounce
|
|
3516
|
-
- \`spring()\` function works well: low mass (0.5), moderate damping (10-12), high stiffness (100-200)
|
|
3517
|
-
- Spring value can map to scale (0 to 1) and opacity (0 to 1)
|
|
3518
|
-
- Consider \`transform-origin\` placement (center for bubbles, top for dropdowns)
|
|
3562
|
+
## Video Types & Source Detection
|
|
3519
3563
|
|
|
3520
|
-
|
|
3521
|
-
- Text entering line-by-line or word-by-word (not all at once)
|
|
3522
|
-
- Can split text into arrays, stagger with delays (index * 5 frames)
|
|
3523
|
-
- \`interpolate()\` works for opacity [0,1] and translateY [20px, 0px] - slide up
|
|
3524
|
-
- Cubic easing works well for slide-up motion
|
|
3564
|
+
Detect the video type and source material FIRST. This determines your asset strategy.
|
|
3525
3565
|
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3566
|
+
| Video Type | Source | Asset Strategy |
|
|
3567
|
+
|------------|--------|----------------|
|
|
3568
|
+
| **Project Launch** | Local codebase | Extract components, branding, screenshots from code |
|
|
3569
|
+
| **Website Promo** | Live URL | Screenshot pages, extract colors/logos via browser |
|
|
3570
|
+
| **News/Trending** | External articles, URLs | Summarize content, use 100% stock media |
|
|
3571
|
+
| **Explainer/Tutorial** | Topic or concept | Research topic, use diagrams + stock |
|
|
3572
|
+
| **Product Announcement** | Press release, changelog | Extract key points, mix branded + stock |
|
|
3533
3573
|
|
|
3534
|
-
|
|
3574
|
+
### Source Detection Logic
|
|
3535
3575
|
|
|
3536
|
-
|
|
3537
|
-
- Static backgrounds feel flat - consider faint dots/patterns
|
|
3538
|
-
- Slow oscillation works well: \`Math.sin(frame / 100)\` applied to position/rotation for "floating" effect
|
|
3539
|
-
- Parallax adds depth: background moves slower than foreground
|
|
3576
|
+
Check what the user provides or what's available:
|
|
3540
3577
|
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3578
|
+
| User Provides | Action |
|
|
3579
|
+
|---------------|--------|
|
|
3580
|
+
| **Local codebase** (package.json, src/) | Extract components, branding, screenshots |
|
|
3581
|
+
| **URL to website** | Screenshot pages, extract colors/logos |
|
|
3582
|
+
| **URL to article/news** | Fetch content, summarize key points |
|
|
3583
|
+
| **Document** (PDF, markdown, .txt) | Parse and extract key messages |
|
|
3584
|
+
| **Raw text/script** | Use directly for voiceover |
|
|
3585
|
+
| **Images/videos** | Use as-is for scenes |
|
|
3586
|
+
| **Topic/concept** | Research + generate stock queries |
|
|
3545
3587
|
|
|
3546
|
-
**
|
|
3547
|
-
-
|
|
3548
|
-
-
|
|
3549
|
-
-
|
|
3588
|
+
**Sources can combine.** Examples:
|
|
3589
|
+
- "Launch video for my project + our blog post" = codebase + URL
|
|
3590
|
+
- "News video about X with our branding" = article + local logo
|
|
3591
|
+
- "Explainer using these screenshots" = user images + generated VO
|
|
3550
3592
|
|
|
3551
|
-
|
|
3593
|
+
---
|
|
3552
3594
|
|
|
3553
|
-
|
|
3554
|
-
- KineticText: text, delay, style props - handles word-splitting and stagger
|
|
3555
|
-
- SmartCard: container with Spring Pop entry and glassmorphism styles
|
|
3556
|
-
- AnimatedCounter: from, to, duration props - number ticking
|
|
3557
|
-
- ProgressBar/ChartElement: percentage, color props - growth animation from 0
|
|
3595
|
+
## Phase 1: Discovery & Analysis
|
|
3558
3596
|
|
|
3559
|
-
|
|
3560
|
-
`;
|
|
3561
|
-
var SVG_ANIMATION_GUIDELINES = `# SVG Line Animation (Write-On Effect)
|
|
3597
|
+
Run the relevant discovery based on detected source type.
|
|
3562
3598
|
|
|
3563
|
-
|
|
3599
|
+
### 1.1 Codebase Analysis (if local project)
|
|
3564
3600
|
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
-
|
|
3568
|
-
- \`strokeDasharray: 1\` with interpolate \`[1, 0]\` over 20-30 frames works well
|
|
3569
|
-
- \`stroke-linecap="round"\` creates friendly hand-drawn look
|
|
3601
|
+
\`\`\`bash
|
|
3602
|
+
# Find branding assets
|
|
3603
|
+
find . -type f \\( -name "logo*" -o -name "favicon*" -o -name "brand*" \\) 2>/dev/null | head -20
|
|
3570
3604
|
|
|
3571
|
-
|
|
3572
|
-
-
|
|
3573
|
-
- Hold: 10 frames
|
|
3574
|
-
- Draw out: fade opacity or continue offset
|
|
3605
|
+
# Find color configuration
|
|
3606
|
+
find . -type f \\( -name "tailwind.config.*" -o -name "theme.*" -o -name "colors.*" \\) 2>/dev/null
|
|
3575
3607
|
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
- Positioning with top/left/scale/rotation props for text accents
|
|
3580
|
-
`;
|
|
3581
|
-
var ASSET_USAGE_GUIDELINES = `# Asset Usage & Optimization
|
|
3608
|
+
# Find impressive UI components (prioritize pages/containers over atoms)
|
|
3609
|
+
find . -path "*/components/*" -name "*.tsx" 2>/dev/null | head -30
|
|
3610
|
+
\`\`\`
|
|
3582
3611
|
|
|
3583
|
-
**
|
|
3612
|
+
**Extract:**
|
|
3613
|
+
- [ ] Logo path (verify exists)
|
|
3614
|
+
- [ ] Primary/accent colors from config
|
|
3615
|
+
- [ ] 2-4 "hero" components worth showcasing
|
|
3584
3616
|
|
|
3585
|
-
|
|
3617
|
+
### 1.2 Website Analysis (if URL provided)
|
|
3586
3618
|
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
- Picture-in-picture style elements
|
|
3591
|
-
- Background layers with reduced opacity
|
|
3592
|
-
- Transitional footage between scenes
|
|
3619
|
+
\`\`\`bash
|
|
3620
|
+
# Scrape website content for analysis
|
|
3621
|
+
${cmd2} scrape "https://example.com" --format json
|
|
3593
3622
|
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
- Embedded elements within compositions
|
|
3597
|
-
- UI component content (cards, panels)
|
|
3598
|
-
- Layered for depth and parallax effects
|
|
3623
|
+
# Save content to file for reference
|
|
3624
|
+
${cmd2} scrape "https://example.com" -o ./content/homepage.md
|
|
3599
3625
|
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
- WebGL shaders for dynamic effects
|
|
3605
|
-
- Combines well with static assets for depth
|
|
3626
|
+
# Scrape multiple pages
|
|
3627
|
+
${cmd2} scrape "https://example.com/features" -o ./content/features.md
|
|
3628
|
+
${cmd2} scrape "https://example.com/pricing" -o ./content/pricing.md
|
|
3629
|
+
\`\`\`
|
|
3606
3630
|
|
|
3607
|
-
**
|
|
3608
|
-
|
|
3631
|
+
**Extract from scraped content:**
|
|
3632
|
+
- [ ] Main value proposition / headline
|
|
3633
|
+
- [ ] Key features and benefits
|
|
3634
|
+
- [ ] Brand name and tagline
|
|
3635
|
+
- [ ] Color mentions (if in content) or use stock visuals
|
|
3609
3636
|
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3637
|
+
### 1.3 Content Analysis (if document/article)
|
|
3638
|
+
|
|
3639
|
+
For news articles, blog posts, press releases, changelogs:
|
|
3640
|
+
|
|
3641
|
+
\`\`\`bash
|
|
3642
|
+
# Scrape and parse article
|
|
3643
|
+
${cmd2} scrape "https://example.com/article" -o ./content.md
|
|
3644
|
+
|
|
3645
|
+
# Or read local document
|
|
3646
|
+
cat ./CHANGELOG.md | head -100
|
|
3647
|
+
\`\`\`
|
|
3648
|
+
|
|
3649
|
+
**Extract:**
|
|
3650
|
+
- [ ] Main headline / title
|
|
3651
|
+
- [ ] 3-5 key points for scenes
|
|
3652
|
+
- [ ] Quotes or stats to highlight
|
|
3653
|
+
- [ ] Related images (if embedded)
|
|
3654
|
+
|
|
3655
|
+
### 1.4 User-Provided Content
|
|
3656
|
+
|
|
3657
|
+
If user provides text, script, or topic directly:
|
|
3617
3658
|
|
|
3618
|
-
|
|
3659
|
+
**Raw script provided:**
|
|
3660
|
+
- Use as-is for voiceover
|
|
3661
|
+
- Plan visuals based on content
|
|
3619
3662
|
|
|
3620
|
-
|
|
3663
|
+
**Topic/concept provided:**
|
|
3664
|
+
- Research topic using your web search capabilities
|
|
3665
|
+
- Or scrape relevant URLs: \`${cmd2} scrape "https://relevant-article.com"\`
|
|
3666
|
+
|
|
3667
|
+
**Images/videos provided:**
|
|
3668
|
+
- Verify files exist
|
|
3669
|
+
- Note dimensions and quality
|
|
3670
|
+
- Plan scenes around provided assets
|
|
3671
|
+
|
|
3672
|
+
**Extract:**
|
|
3673
|
+
- [ ] Key messages (3-5 per video)
|
|
3674
|
+
- [ ] Visual concepts for each message
|
|
3675
|
+
- [ ] Any specific assets user wants included
|
|
3676
|
+
|
|
3677
|
+
### 1.5 Content Brief & User Clarification
|
|
3678
|
+
|
|
3679
|
+
**Goal:** Align on video purpose before scripting.
|
|
3680
|
+
|
|
3681
|
+
**Use AskUserQuestion tool:** If your AI environment provides an \`AskUserQuestion\` tool (Claude Code, Agent SDK, etc.), use it to gather user preferences about duration, tone, focus, and CTA before proceeding. This provides a better UX than plain text questions.
|
|
3682
|
+
|
|
3683
|
+
**When to ask vs. proceed:**
|
|
3684
|
+
- **Vague request** ("make a video for my project") \u2192 ASK clarifying questions
|
|
3685
|
+
- **Partial details** ("30-second TikTok for my app") \u2192 ASK remaining questions
|
|
3686
|
+
- **Detailed brief** (duration, tone, CTA specified) \u2192 PROCEED directly
|
|
3687
|
+
- **User says "just do it" or "use defaults"** \u2192 USE defaults below
|
|
3688
|
+
|
|
3689
|
+
**Reasonable defaults (if user opts out of questions):**
|
|
3690
|
+
- Duration: 30-45 seconds
|
|
3691
|
+
- Tone: Professional
|
|
3692
|
+
- Focus: Balanced (show problem + solution)
|
|
3693
|
+
- CTA: "Try it free" or "Learn more"
|
|
3694
|
+
- Structure: Hook \u2192 Main Point \u2192 CTA
|
|
3695
|
+
|
|
3696
|
+
**Validation Gate:** Do NOT proceed to asset generation until you have:
|
|
3697
|
+
- [ ] Clear video type identified
|
|
3698
|
+
- [ ] Source material gathered (screenshots, content, or stock queries planned)
|
|
3699
|
+
- [ ] Duration and tone (confirmed OR defaulted)
|
|
3621
3700
|
|
|
3622
3701
|
---
|
|
3623
3702
|
|
|
3624
|
-
##
|
|
3703
|
+
## Phase 2: Script & Scene Planning
|
|
3625
3704
|
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3705
|
+
### 2.1 Narrative Structure
|
|
3706
|
+
|
|
3707
|
+
Follow this arc for maximum engagement:
|
|
3708
|
+
|
|
3709
|
+
| Scene | Duration | Purpose | Example |
|
|
3710
|
+
|-------|----------|---------|---------|
|
|
3711
|
+
| **Hook** | 3-5s | Stop the scroll, create curiosity | "What if your dashboard updated itself?" |
|
|
3712
|
+
| **Problem** | 5-8s | Relatable pain point | "Tired of manual data entry?" |
|
|
3713
|
+
| **Solution** | 10-20s | Show the product/concept | Demo of key features |
|
|
3714
|
+
| **Proof** | 5-10s | Social proof, stats, benefits | "10x faster than competitors" |
|
|
3715
|
+
| **CTA** | 3-5s | Clear next step | "Try free at example.com" |
|
|
3716
|
+
|
|
3717
|
+
**For Short Videos (15-30s):** Hook \u2192 Solution \u2192 CTA (skip Problem/Proof)
|
|
3718
|
+
|
|
3719
|
+
### 2.2 Scene Definition
|
|
3720
|
+
|
|
3721
|
+
For each scene, define:
|
|
3722
|
+
|
|
3723
|
+
\`\`\`json
|
|
3724
|
+
{
|
|
3725
|
+
"name": "SceneName",
|
|
3726
|
+
"script": "Voiceover text (conversational, 2-3 sentences max)",
|
|
3727
|
+
"imageQuery": "Stock search query if needed",
|
|
3728
|
+
"videoQuery": "Stock video search query if preferred over image",
|
|
3729
|
+
"componentPath": "src/components/Feature.tsx (Project Mode only, VERIFIED path)"
|
|
3730
|
+
}
|
|
3629
3731
|
\`\`\`
|
|
3630
3732
|
|
|
3733
|
+
**Script Writing Tips:**
|
|
3734
|
+
- Keep sentences SHORT (8-12 words ideal for voiceover)
|
|
3735
|
+
- Use active voice: "Build faster" not "Faster building is possible"
|
|
3736
|
+
- Include natural pauses with periods, not commas
|
|
3737
|
+
- Match script length to desired scene duration (~150 words/minute)
|
|
3738
|
+
|
|
3631
3739
|
---
|
|
3632
3740
|
|
|
3633
|
-
##
|
|
3741
|
+
## Phase 3: Asset Generation
|
|
3634
3742
|
|
|
3635
|
-
### 1
|
|
3743
|
+
### 3.1 Generate Voiceovers & Music
|
|
3636
3744
|
|
|
3637
|
-
|
|
3745
|
+
**CRITICAL:** Run this command with your scenes JSON. Music is generated LAST to match total duration.
|
|
3638
3746
|
|
|
3639
3747
|
\`\`\`bash
|
|
3640
|
-
cat <<
|
|
3748
|
+
cat <<'SCENES_JSON' | ${cmd2} video create --output ./public
|
|
3641
3749
|
{
|
|
3642
3750
|
"scenes": [
|
|
3643
|
-
{
|
|
3644
|
-
"name": "Hook",
|
|
3645
|
-
"script": "
|
|
3646
|
-
"imageQuery": "
|
|
3751
|
+
{
|
|
3752
|
+
"name": "Hook",
|
|
3753
|
+
"script": "Your hook script here.",
|
|
3754
|
+
"imageQuery": "abstract tech gradient particles"
|
|
3647
3755
|
},
|
|
3648
|
-
{
|
|
3649
|
-
"name": "
|
|
3650
|
-
"script": "
|
|
3756
|
+
{
|
|
3757
|
+
"name": "Solution",
|
|
3758
|
+
"script": "Your solution script here.",
|
|
3759
|
+
"videoQuery": "modern dashboard interface animation"
|
|
3760
|
+
},
|
|
3761
|
+
{
|
|
3762
|
+
"name": "CTA",
|
|
3763
|
+
"script": "Your call to action here.",
|
|
3764
|
+
"imageQuery": "gradient background call to action"
|
|
3651
3765
|
}
|
|
3652
3766
|
],
|
|
3653
|
-
"
|
|
3767
|
+
"voiceId": "21m00Tcm4TlvDq8ikWAM",
|
|
3768
|
+
"voiceSettings": {
|
|
3769
|
+
"speed": 1.0,
|
|
3770
|
+
"stability": 0.5,
|
|
3771
|
+
"similarity": 0.75,
|
|
3772
|
+
"style": 0.3
|
|
3773
|
+
},
|
|
3774
|
+
"musicPrompt": "upbeat corporate, modern synth, positive energy"
|
|
3654
3775
|
}
|
|
3655
|
-
|
|
3776
|
+
SCENES_JSON
|
|
3656
3777
|
\`\`\`
|
|
3657
3778
|
|
|
3658
|
-
**
|
|
3659
|
-
|
|
3660
|
-
- \`
|
|
3661
|
-
- \`
|
|
3779
|
+
**Voice ID:** Use ElevenLabs voice IDs. Get available voices with \`${cmd2} tts voices\`.
|
|
3780
|
+
Common voice IDs:
|
|
3781
|
+
- \`21m00Tcm4TlvDq8ikWAM\` - Rachel (default, calm female)
|
|
3782
|
+
- \`EXAVITQu4vr4xnSDxMaL\` - Bella (young female)
|
|
3783
|
+
- \`ErXwobaYiN019PkySvjV\` - Antoni (male)
|
|
3662
3784
|
|
|
3663
|
-
|
|
3785
|
+
**Voice Settings Tuning:**
|
|
3786
|
+
| Setting | Low (0.2-0.4) | Medium (0.5) | High (0.6-0.8) |
|
|
3787
|
+
|---------|---------------|--------------|----------------|
|
|
3788
|
+
| stability | More expressive/variable | Balanced | Consistent/monotone |
|
|
3789
|
+
| similarity | Creative interpretation | Balanced | Strict voice match |
|
|
3790
|
+
| style | Subtle emotion | Moderate | Dramatic/animated |
|
|
3791
|
+
| speed | Slower, dramatic | Normal | Faster, energetic |
|
|
3664
3792
|
|
|
3665
|
-
|
|
3793
|
+
### 3.2 Search Additional Stock Media (Optional)
|
|
3794
|
+
|
|
3795
|
+
If scenes need more visuals:
|
|
3666
3796
|
|
|
3667
3797
|
\`\`\`bash
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3798
|
+
# Search stock images
|
|
3799
|
+
${cmd2} image search "modern SaaS dashboard dark theme" --count 5
|
|
3800
|
+
|
|
3801
|
+
# Search stock videos
|
|
3802
|
+
${cmd2} video search "tech particles animation blue" --license free
|
|
3671
3803
|
\`\`\`
|
|
3672
3804
|
|
|
3673
|
-
### 3.
|
|
3805
|
+
### 3.3 Verify Generated Assets
|
|
3674
3806
|
|
|
3675
|
-
|
|
3676
|
-
- First render: \`out/video-v1.mp4\`
|
|
3677
|
-
- Re-render: \`out/video-v2.mp4\`, \`out/video-v3.mp4\`, etc.
|
|
3807
|
+
After CLI completes, verify all files exist:
|
|
3678
3808
|
|
|
3679
|
-
**For landscape videos (16:9):**
|
|
3680
3809
|
\`\`\`bash
|
|
3681
|
-
|
|
3810
|
+
ls -la ./public/audio/
|
|
3811
|
+
ls -la ./public/images/
|
|
3812
|
+
ls -la ./public/videos/
|
|
3813
|
+
cat ./public/video-manifest.json
|
|
3682
3814
|
\`\`\`
|
|
3683
3815
|
|
|
3684
|
-
**
|
|
3816
|
+
**Validation Gate:** Ensure:
|
|
3817
|
+
- [ ] Each scene has an audio file (\`.wav\` or \`.mp3\`)
|
|
3818
|
+
- [ ] Music file exists (\`audio/music.mp3\`)
|
|
3819
|
+
- [ ] video-manifest.json is valid JSON
|
|
3820
|
+
- [ ] Total duration looks reasonable for content
|
|
3821
|
+
|
|
3822
|
+
---
|
|
3823
|
+
|
|
3824
|
+
## Phase 4: Manifest Enrichment
|
|
3825
|
+
|
|
3826
|
+
After CLI generates base manifest, enhance it with metadata based on your source type.
|
|
3827
|
+
|
|
3828
|
+
**Add these fields as relevant:**
|
|
3829
|
+
|
|
3830
|
+
\`\`\`json
|
|
3831
|
+
{
|
|
3832
|
+
"source": "codebase|website|article|topic",
|
|
3833
|
+
"sourceUrl": "https://... (if external)",
|
|
3834
|
+
|
|
3835
|
+
"scenes": [
|
|
3836
|
+
{
|
|
3837
|
+
"componentPath": "src/components/X.tsx",
|
|
3838
|
+
"screenshotPath": "screenshots/home.png",
|
|
3839
|
+
"textOverlay": "Key message here"
|
|
3840
|
+
}
|
|
3841
|
+
],
|
|
3842
|
+
|
|
3843
|
+
"theme": {
|
|
3844
|
+
"primary": "#3b82f6",
|
|
3845
|
+
"accent": "#10b981"
|
|
3846
|
+
},
|
|
3847
|
+
|
|
3848
|
+
"branding": {
|
|
3849
|
+
"logoPath": "public/logo.svg",
|
|
3850
|
+
"companyName": "Name"
|
|
3851
|
+
},
|
|
3852
|
+
|
|
3853
|
+
"attribution": {
|
|
3854
|
+
"source": "SourceName",
|
|
3855
|
+
"date": "2024-01-15"
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
\`\`\`
|
|
3859
|
+
|
|
3860
|
+
**Key rules:**
|
|
3861
|
+
- Only add \`componentPath\` for VERIFIED files
|
|
3862
|
+
- Only add \`screenshotPath\` if you captured screenshots
|
|
3863
|
+
- Only add \`attribution\` for news/article sources
|
|
3864
|
+
- \`theme\` and \`branding\` only if extracted from actual source
|
|
3865
|
+
|
|
3866
|
+
---
|
|
3867
|
+
|
|
3868
|
+
## Output Checklist
|
|
3869
|
+
|
|
3870
|
+
Before completing Phase 1, verify:
|
|
3871
|
+
|
|
3872
|
+
**Required for ALL videos:**
|
|
3873
|
+
- [ ] \`./public/audio/\` contains voiceover for each scene
|
|
3874
|
+
- [ ] \`./public/audio/music.mp3\` exists (or user opted out)
|
|
3875
|
+
- [ ] \`./public/video-manifest.json\` is valid JSON
|
|
3876
|
+
- [ ] Each scene has visual source (image, video, screenshot, or componentPath)
|
|
3877
|
+
|
|
3878
|
+
**If using local codebase:**
|
|
3879
|
+
- [ ] All \`componentPath\` references VERIFIED to exist
|
|
3880
|
+
- [ ] Theme colors extracted from actual config
|
|
3881
|
+
- [ ] Logo path verified
|
|
3882
|
+
|
|
3883
|
+
**If using website URL:**
|
|
3884
|
+
- [ ] Screenshots captured for key pages
|
|
3885
|
+
- [ ] Colors/branding extracted or noted
|
|
3886
|
+
|
|
3887
|
+
**If news/content video:**
|
|
3888
|
+
- [ ] Source attribution included
|
|
3889
|
+
- [ ] Key points extracted for scenes
|
|
3890
|
+
|
|
3891
|
+
**Success Message:**
|
|
3892
|
+
\`\`\`
|
|
3893
|
+
\u2705 Phase 1 Complete: Video assets assembled
|
|
3894
|
+
- Video type: [project/website/news/explainer]
|
|
3895
|
+
- Scenes: X
|
|
3896
|
+
- Total duration: ~Xs
|
|
3897
|
+
- Audio files: X
|
|
3898
|
+
- Visuals: X images, X videos, X screenshots
|
|
3899
|
+
- Components to adapt: X (if any)
|
|
3900
|
+
|
|
3901
|
+
Ready for Phase 2: Remotion implementation
|
|
3902
|
+
\`\`\`
|
|
3903
|
+
|
|
3904
|
+
---
|
|
3905
|
+
|
|
3906
|
+
## Handoff to Phase 2: Remotion Setup
|
|
3907
|
+
|
|
3908
|
+
After Phase 1 is complete, prepare the Remotion project:
|
|
3909
|
+
|
|
3910
|
+
### Step 1: Initialize Remotion Project
|
|
3911
|
+
|
|
3685
3912
|
\`\`\`bash
|
|
3686
|
-
|
|
3687
|
-
|
|
3913
|
+
# Create Remotion project in current directory
|
|
3914
|
+
${cmd2} video init my-video
|
|
3915
|
+
|
|
3916
|
+
# For TikTok/Reels format (9:16)
|
|
3917
|
+
${cmd2} video init my-video --type tiktok
|
|
3688
3918
|
\`\`\`
|
|
3689
3919
|
|
|
3690
|
-
|
|
3920
|
+
This creates \`./my-video/\` with the Remotion template.
|
|
3921
|
+
|
|
3922
|
+
### Step 2: Copy Assets to Remotion Project
|
|
3691
3923
|
|
|
3692
|
-
|
|
3924
|
+
\`\`\`bash
|
|
3925
|
+
# Copy all generated assets to Remotion public folder
|
|
3926
|
+
cp -r ./public/audio ./my-video/public/
|
|
3927
|
+
cp -r ./public/images ./my-video/public/
|
|
3928
|
+
cp -r ./public/videos ./my-video/public/
|
|
3929
|
+
cp ./public/video-manifest.json ./my-video/public/
|
|
3930
|
+
\`\`\`
|
|
3931
|
+
|
|
3932
|
+
### Step 3: Verify Transfer
|
|
3693
3933
|
|
|
3694
3934
|
\`\`\`bash
|
|
3695
|
-
|
|
3935
|
+
# Confirm all assets are in place
|
|
3936
|
+
ls -la ./my-video/public/
|
|
3937
|
+
cat ./my-video/public/video-manifest.json | jq '.scenes | length'
|
|
3938
|
+
\`\`\`
|
|
3939
|
+
|
|
3940
|
+
**Expected structure in Remotion project:**
|
|
3941
|
+
\`\`\`
|
|
3942
|
+
my-video/
|
|
3943
|
+
\u251C\u2500\u2500 public/
|
|
3944
|
+
\u2502 \u251C\u2500\u2500 audio/
|
|
3945
|
+
\u2502 \u2502 \u251C\u2500\u2500 hook.wav
|
|
3946
|
+
\u2502 \u2502 \u251C\u2500\u2500 solution.wav
|
|
3947
|
+
\u2502 \u2502 \u251C\u2500\u2500 cta.wav
|
|
3948
|
+
\u2502 \u2502 \u2514\u2500\u2500 music.mp3
|
|
3949
|
+
\u2502 \u251C\u2500\u2500 images/
|
|
3950
|
+
\u2502 \u2502 \u2514\u2500\u2500 *.jpg, *.png
|
|
3951
|
+
\u2502 \u251C\u2500\u2500 videos/
|
|
3952
|
+
\u2502 \u2502 \u2514\u2500\u2500 *.mp4
|
|
3953
|
+
\u2502 \u2514\u2500\u2500 video-manifest.json
|
|
3954
|
+
\u251C\u2500\u2500 src/
|
|
3955
|
+
\u2502 \u2514\u2500\u2500 ... (Remotion components)
|
|
3956
|
+
\u2514\u2500\u2500 package.json
|
|
3957
|
+
\`\`\`
|
|
3958
|
+
|
|
3959
|
+
### Step 4: Hand Off to Phase 2
|
|
3960
|
+
|
|
3961
|
+
\`\`\`
|
|
3962
|
+
\u{1F4E6} Assets transferred to Remotion project: ./my-video/
|
|
3963
|
+
|
|
3964
|
+
Next steps (Phase 2 - Remotion Implementation):
|
|
3965
|
+
cd my-video
|
|
3966
|
+
pnpm dev # Preview in Remotion Studio
|
|
3967
|
+
# Then implement scenes using video-manifest.json
|
|
3696
3968
|
\`\`\`
|
|
3697
3969
|
|
|
3970
|
+
**Note:** Phase 2 (Remotion implementation) is handled by a separate skill.
|
|
3971
|
+
|
|
3698
3972
|
---
|
|
3699
3973
|
|
|
3700
|
-
|
|
3974
|
+
## Examples
|
|
3975
|
+
|
|
3976
|
+
### Example 1: News Video
|
|
3977
|
+
**User says:** "Make a video about the latest AI news"
|
|
3978
|
+
|
|
3979
|
+
**Actions:**
|
|
3980
|
+
1. Ask: "Any specific article or topic? What duration (30s or 60s)?"
|
|
3981
|
+
2. User provides article URL or topic
|
|
3982
|
+
3. Fetch/research content, extract 3-4 key points
|
|
3983
|
+
4. Write script with Hook \u2192 Key Points \u2192 Takeaway
|
|
3984
|
+
5. Run CLI with stock video queries for each point
|
|
3985
|
+
6. Generate manifest with source attribution
|
|
3986
|
+
|
|
3987
|
+
**Result:** 45-second news video with stock footage, voiceover, and music
|
|
3701
3988
|
|
|
3702
3989
|
---
|
|
3703
3990
|
|
|
3704
|
-
|
|
3991
|
+
### Example 2: Product Launch (with codebase)
|
|
3992
|
+
**User says:** "Create a promo video for my app"
|
|
3993
|
+
|
|
3994
|
+
**Actions:**
|
|
3995
|
+
1. Scan project: find logo, colors, impressive components
|
|
3996
|
+
2. Ask: "Which features to highlight? Duration preference?"
|
|
3997
|
+
3. Write script: Hook \u2192 Problem \u2192 Feature Demo \u2192 CTA
|
|
3998
|
+
4. Run CLI with scenes, use componentPath for demo scenes
|
|
3999
|
+
5. Enrich manifest with theme colors and branding
|
|
4000
|
+
|
|
4001
|
+
**Result:** 60-second promo with branded visuals and component references
|
|
3705
4002
|
|
|
3706
4003
|
---
|
|
3707
4004
|
|
|
3708
|
-
|
|
4005
|
+
### Example 3: Website Promo (URL only)
|
|
4006
|
+
**User says:** "Make a video for https://example.com"
|
|
4007
|
+
|
|
4008
|
+
**Actions:**
|
|
4009
|
+
1. Scrape website content: \`${cmd2} scrape "https://example.com" -o content.md\`
|
|
4010
|
+
2. Extract key messages, features, and value props from content
|
|
4011
|
+
3. Write script based on scraped content
|
|
4012
|
+
4. Run CLI with stock media queries matching the product/service
|
|
4013
|
+
5. Use text overlays for key messages
|
|
4014
|
+
|
|
4015
|
+
**Result:** 30-second website promo with stock visuals and key messaging from site
|
|
4016
|
+
|
|
4017
|
+
---
|
|
4018
|
+
|
|
4019
|
+
### Example 4: Explainer (topic only)
|
|
4020
|
+
**User says:** "Explain how blockchain works in 30 seconds"
|
|
4021
|
+
|
|
4022
|
+
**Actions:**
|
|
4023
|
+
1. Research topic briefly if needed
|
|
4024
|
+
2. Write simple script: Concept \u2192 How it works \u2192 Why it matters
|
|
4025
|
+
3. Run CLI with visual metaphor queries ("digital ledger", "chain links")
|
|
4026
|
+
4. Use 100% stock media
|
|
4027
|
+
|
|
4028
|
+
**Result:** 30-second explainer with abstract visualizations
|
|
4029
|
+
|
|
4030
|
+
---
|
|
4031
|
+
|
|
4032
|
+
## Error Recovery
|
|
4033
|
+
|
|
4034
|
+
Use standalone CLI commands if \`video create\` fails partially.
|
|
4035
|
+
|
|
4036
|
+
### If TTS Fails for One Scene
|
|
4037
|
+
|
|
4038
|
+
\`\`\`bash
|
|
4039
|
+
# Retry single scene with standalone tts command
|
|
4040
|
+
${cmd2} tts "Your script text here" --voice Kore --output ./public/audio/scene-name.wav
|
|
4041
|
+
\`\`\`
|
|
4042
|
+
|
|
4043
|
+
If still fails: try different voice, or skip scene.
|
|
4044
|
+
|
|
4045
|
+
### If Music Generation Fails
|
|
4046
|
+
|
|
4047
|
+
\`\`\`bash
|
|
4048
|
+
# Retry music separately
|
|
4049
|
+
${cmd2} music generate "upbeat corporate synth" --duration 30 --output ./public/audio/music.mp3
|
|
4050
|
+
\`\`\`
|
|
4051
|
+
|
|
4052
|
+
If still fails: continue without music, notify user.
|
|
4053
|
+
|
|
4054
|
+
### If Stock Search Returns Nothing
|
|
4055
|
+
|
|
4056
|
+
\`\`\`bash
|
|
4057
|
+
# Try standalone image search with simpler query
|
|
4058
|
+
${cmd2} image search "dashboard" --count 10
|
|
4059
|
+
|
|
4060
|
+
# Or try video search
|
|
4061
|
+
${cmd2} video search "tech animation" --license free
|
|
4062
|
+
\`\`\`
|
|
4063
|
+
|
|
4064
|
+
Fallback: use solid color background with text overlay.
|
|
4065
|
+
|
|
4066
|
+
### If Component Not Found
|
|
4067
|
+
1. DO NOT guess or hallucinate path
|
|
4068
|
+
2. Fall back to stock media for that scene
|
|
4069
|
+
3. Add to manifest: \`"componentPath": null, "fallbackReason": "not found"\`
|
|
3709
4070
|
|
|
3710
4071
|
---
|
|
4072
|
+
|
|
4073
|
+
## Troubleshooting
|
|
4074
|
+
|
|
4075
|
+
### CLI Command Fails
|
|
4076
|
+
|
|
4077
|
+
**Error:** \`command not found: ${cmd2}\`
|
|
4078
|
+
**Fix:** Install CLI globally: \`npm install -g @anthropic/${name}\` or use npx: \`npx ${cmd2} video create\`
|
|
4079
|
+
|
|
4080
|
+
**Error:** \`Authentication required\`
|
|
4081
|
+
**Fix:** Run \`${cmd2} login\` to authenticate with API key
|
|
4082
|
+
|
|
4083
|
+
### Audio Generation Issues
|
|
4084
|
+
|
|
4085
|
+
**Error:** \`Voice not found\`
|
|
4086
|
+
**Fix:** Use one of: Kore, Puck, Rachel, alloy (case-sensitive)
|
|
4087
|
+
|
|
4088
|
+
**Error:** \`Music duration too short\`
|
|
4089
|
+
**Cause:** ElevenLabs requires minimum 3 seconds
|
|
4090
|
+
**Fix:** Ensure total script duration is at least 5 seconds
|
|
4091
|
+
|
|
4092
|
+
### Stock Search Returns Nothing
|
|
4093
|
+
|
|
4094
|
+
**Cause:** Query too specific or API limit reached
|
|
4095
|
+
**Fix:**
|
|
4096
|
+
1. Simplify query: "dashboard" instead of "modern SaaS dashboard with dark theme"
|
|
4097
|
+
2. Try alternative terms: "interface" instead of "UI"
|
|
4098
|
+
3. Check API quota: \`${cmd2} account\`
|
|
4099
|
+
|
|
4100
|
+
### Component Path Not Found
|
|
4101
|
+
|
|
4102
|
+
**Cause:** Guessed path without verification
|
|
4103
|
+
**Fix:**
|
|
4104
|
+
1. ALWAYS run \`ls\` or \`find\` before referencing
|
|
4105
|
+
2. Use stock media as fallback
|
|
4106
|
+
3. Add to manifest: \`"componentPath": null, "fallback": "stock"\`
|
|
4107
|
+
|
|
4108
|
+
### Manifest JSON Invalid
|
|
4109
|
+
|
|
4110
|
+
**Cause:** Syntax error in manual edits
|
|
4111
|
+
**Fix:** Validate JSON before saving: \`cat video-manifest.json | jq .\`
|
|
4112
|
+
|
|
4113
|
+
---
|
|
4114
|
+
|
|
4115
|
+
## Quick Reference
|
|
4116
|
+
|
|
4117
|
+
### Minimum Viable Command
|
|
4118
|
+
\`\`\`bash
|
|
4119
|
+
cat <<'EOF' | ${cmd2} video create --output ./public
|
|
4120
|
+
{"scenes":[{"name":"Main","script":"Your script here."}],"musicPrompt":"ambient background"}
|
|
4121
|
+
EOF
|
|
4122
|
+
\`\`\`
|
|
4123
|
+
|
|
4124
|
+
### Full Command with All Options
|
|
4125
|
+
\`\`\`bash
|
|
4126
|
+
cat <<'EOF' | ${cmd2} video create --output ./public
|
|
4127
|
+
{
|
|
4128
|
+
"scenes": [
|
|
4129
|
+
{"name": "Hook", "script": "...", "imageQuery": "..."},
|
|
4130
|
+
{"name": "Demo", "script": "...", "videoQuery": "..."},
|
|
4131
|
+
{"name": "CTA", "script": "...", "imageQuery": "..."}
|
|
4132
|
+
],
|
|
4133
|
+
"voiceId": "21m00Tcm4TlvDq8ikWAM",
|
|
4134
|
+
"voiceSettings": {"speed": 1.0, "stability": 0.5, "similarity": 0.75, "style": 0.3},
|
|
4135
|
+
"musicPrompt": "genre, mood, instruments"
|
|
4136
|
+
}
|
|
4137
|
+
EOF
|
|
4138
|
+
\`\`\`
|
|
4139
|
+
|
|
4140
|
+
### Voice Settings Presets
|
|
4141
|
+
| Preset | speed | stability | similarity | style | Best For |
|
|
4142
|
+
|--------|-------|-----------|------------|-------|----------|
|
|
4143
|
+
| Professional | 1.0 | 0.6 | 0.8 | 0.2 | Corporate, B2B |
|
|
4144
|
+
| Energetic | 1.1 | 0.4 | 0.7 | 0.5 | Startups, Apps |
|
|
4145
|
+
| Calm | 0.9 | 0.7 | 0.8 | 0.2 | Tutorial, Explainer |
|
|
4146
|
+
| Dramatic | 0.85 | 0.3 | 0.6 | 0.7 | Announcements |
|
|
4147
|
+
|
|
4148
|
+
---
|
|
4149
|
+
|
|
4150
|
+
## References
|
|
4151
|
+
|
|
4152
|
+
For advanced techniques, consult these files after Phase 1:
|
|
4153
|
+
- \`rules/video/motion-design.md\` - Animation principles
|
|
4154
|
+
- \`rules/video/thumbnails.md\` - CTR optimization
|
|
4155
|
+
- \`rules/video/svg-animations.md\` - Write-on effects
|
|
4156
|
+
- \`rules/video/asset-usage.md\` - Creative asset usage
|
|
3711
4157
|
`;
|
|
3712
4158
|
}
|
|
3713
4159
|
|
|
@@ -3715,7 +4161,7 @@ ${ASSET_USAGE_GUIDELINES}
|
|
|
3715
4161
|
function generatePresentationSkillContent(context) {
|
|
3716
4162
|
const { name, cmd: cmd2 } = context;
|
|
3717
4163
|
return `---
|
|
3718
|
-
name: ${
|
|
4164
|
+
name: ${cmd2}-presentation
|
|
3719
4165
|
description: Use when user asks to create presentations (slides, decks, pitch decks). Generates AI-powered presentations with structured content and professional design.
|
|
3720
4166
|
---
|
|
3721
4167
|
|
|
@@ -3753,8 +4199,12 @@ ${cmd2} create --file product-brief.md
|
|
|
3753
4199
|
|
|
3754
4200
|
### From URL
|
|
3755
4201
|
|
|
4202
|
+
Supports websites, YouTube videos, and Twitter/X posts:
|
|
4203
|
+
|
|
3756
4204
|
\`\`\`bash
|
|
3757
4205
|
${cmd2} create --url https://company.com/product
|
|
4206
|
+
${cmd2} create --url https://youtube.com/watch?v=abc123
|
|
4207
|
+
${cmd2} create --url https://x.com/user/status/123456
|
|
3758
4208
|
\`\`\`
|
|
3759
4209
|
|
|
3760
4210
|
### From Piped Content
|
|
@@ -4745,7 +5195,7 @@ function getExtension(url) {
|
|
|
4745
5195
|
}
|
|
4746
5196
|
return "jpg";
|
|
4747
5197
|
}
|
|
4748
|
-
var createCommand3 = new Command19("create").description("Create video assets (voiceover per scene, music, images)").option("-s, --script <text>", "Narration script (legacy single-script mode)").option("--script-file <path>", "Path to script file (legacy) or scenes JSON").option("-t, --topic <text>", "Topic for image search").option("-v, --voice <name>", "TTS voice (
|
|
5198
|
+
var createCommand3 = new Command19("create").description("Create video assets (voiceover per scene, music, images)").option("-s, --script <text>", "Narration script (legacy single-script mode)").option("--script-file <path>", "Path to script file (legacy) or scenes JSON").option("-t, --topic <text>", "Topic for image search").option("-v, --voice <name>", "TTS voice ID (ElevenLabs: Rachel, Josh, Adam; OpenAI: alloy, nova; Gemini: Kore, Puck)").option("-m, --music-prompt <text>", "Music description").option("-n, --num-images <number>", "Number of images to search/download", "5").option("-o, --output <dir>", "Output directory", "./public").option("-f, --format <format>", "Output format: human, json, quiet", "human").action(async (options) => {
|
|
4749
5199
|
const format = options.format;
|
|
4750
5200
|
const spinner = format === "human" ? ora12("Initializing...").start() : null;
|
|
4751
5201
|
try {
|
|
@@ -4771,6 +5221,7 @@ var createCommand3 = new Command19("create").description("Create video assets (v
|
|
|
4771
5221
|
}
|
|
4772
5222
|
}
|
|
4773
5223
|
const voice = scenesInput?.voice || options.voice;
|
|
5224
|
+
const voiceId = scenesInput?.voiceId;
|
|
4774
5225
|
const musicPrompt = scenesInput?.musicPrompt || options.musicPrompt || "uplifting background music, positive energy";
|
|
4775
5226
|
const audioDir = join2(options.output, "audio");
|
|
4776
5227
|
const imagesDir = join2(options.output, "images");
|
|
@@ -4799,6 +5250,8 @@ var createCommand3 = new Command19("create").description("Create video assets (v
|
|
|
4799
5250
|
texts: ttsRequests,
|
|
4800
5251
|
options: {
|
|
4801
5252
|
voice,
|
|
5253
|
+
voiceId,
|
|
5254
|
+
// ElevenLabs voice ID takes priority on backend
|
|
4802
5255
|
voiceSettings: scenesInput.voiceSettings
|
|
4803
5256
|
}
|
|
4804
5257
|
});
|
|
@@ -4956,7 +5409,7 @@ var createCommand3 = new Command19("create").description("Create video assets (v
|
|
|
4956
5409
|
timeline.elements.length > 0 ? Math.max(...timeline.elements.map((e) => e.endMs)) : 0
|
|
4957
5410
|
);
|
|
4958
5411
|
const actualVideoDuration = videoEndTimeMs / 1e3;
|
|
4959
|
-
const musicDuration = Math.min(
|
|
5412
|
+
const musicDuration = Math.min(300, Math.ceil(actualVideoDuration));
|
|
4960
5413
|
console.log(`[Music Generation] Requesting music:`, {
|
|
4961
5414
|
prompt: musicPrompt,
|
|
4962
5415
|
requestedDuration: musicDuration,
|
|
@@ -4965,71 +5418,107 @@ var createCommand3 = new Command19("create").description("Create video assets (v
|
|
|
4965
5418
|
timelineDurationMs: videoEndTimeMs
|
|
4966
5419
|
});
|
|
4967
5420
|
let musicInfo;
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
5421
|
+
let thumbnailPath;
|
|
5422
|
+
if (spinner) spinner.text = "Generating music and thumbnail...";
|
|
5423
|
+
const firstScene = scenes[0];
|
|
5424
|
+
const thumbnailPrompt = `YouTube thumbnail, bold text overlay, high contrast, vibrant colors, 16:9 aspect ratio: ${firstScene?.text?.slice(0, 100) || "video thumbnail"}`;
|
|
5425
|
+
const parallelTasks = [];
|
|
5426
|
+
const musicTask = (async () => {
|
|
5427
|
+
if (musicDuration < 3) {
|
|
5428
|
+
if (format === "human") {
|
|
5429
|
+
spinner?.stop();
|
|
5430
|
+
warn(`Video duration (${actualVideoDuration.toFixed(1)}s) is too short for music generation (minimum 3s).`);
|
|
5431
|
+
spinner?.start();
|
|
5432
|
+
}
|
|
5433
|
+
return null;
|
|
4974
5434
|
}
|
|
4975
|
-
} else {
|
|
4976
5435
|
try {
|
|
4977
|
-
|
|
4978
|
-
let musicResult = await generateMusic({
|
|
5436
|
+
let musicResult2 = await generateMusic({
|
|
4979
5437
|
prompt: musicPrompt,
|
|
4980
5438
|
duration: musicDuration
|
|
4981
5439
|
});
|
|
4982
|
-
if (
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
() => checkMusicStatus(musicResult.requestId),
|
|
5440
|
+
if (musicResult2.status !== "completed" && musicResult2.status !== "failed") {
|
|
5441
|
+
musicResult2 = await pollForCompletion(
|
|
5442
|
+
() => checkMusicStatus(musicResult2.requestId),
|
|
4986
5443
|
60,
|
|
4987
5444
|
2e3
|
|
4988
5445
|
);
|
|
4989
5446
|
}
|
|
4990
|
-
if (
|
|
4991
|
-
throw new Error(
|
|
5447
|
+
if (musicResult2.status === "failed") {
|
|
5448
|
+
throw new Error(musicResult2.error || "Unknown error");
|
|
4992
5449
|
}
|
|
4993
5450
|
const musicPath = join2(audioDir, "music.mp3");
|
|
4994
|
-
if (
|
|
4995
|
-
await downloadFile3(
|
|
5451
|
+
if (musicResult2.audioUrl) {
|
|
5452
|
+
await downloadFile3(musicResult2.audioUrl, musicPath);
|
|
4996
5453
|
}
|
|
4997
|
-
|
|
4998
|
-
const actualMusicDuration = musicResult.duration || musicDuration;
|
|
4999
|
-
console.log(`[Music Generation] Received music:`, {
|
|
5000
|
-
requestedDuration: musicDuration,
|
|
5001
|
-
returnedDuration: musicResult.duration,
|
|
5002
|
-
actualUsedDuration: actualMusicDuration,
|
|
5003
|
-
totalAudioDuration: totalDuration,
|
|
5004
|
-
difference: actualMusicDuration - totalDuration,
|
|
5005
|
-
audioUrl: musicResult.audioUrl?.substring(0, 50) + "..."
|
|
5006
|
-
});
|
|
5007
|
-
musicInfo = {
|
|
5454
|
+
return {
|
|
5008
5455
|
path: "audio/music.mp3",
|
|
5009
|
-
duration:
|
|
5456
|
+
duration: musicResult2.duration || musicDuration,
|
|
5010
5457
|
prompt: musicPrompt,
|
|
5011
|
-
cost:
|
|
5458
|
+
cost: musicResult2.cost || 0
|
|
5012
5459
|
};
|
|
5460
|
+
} catch (err) {
|
|
5013
5461
|
if (format === "human") {
|
|
5014
5462
|
spinner?.stop();
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5463
|
+
warn(`Music generation failed: ${err.message}`);
|
|
5464
|
+
spinner?.start();
|
|
5465
|
+
}
|
|
5466
|
+
return null;
|
|
5467
|
+
}
|
|
5468
|
+
})();
|
|
5469
|
+
parallelTasks.push(musicTask);
|
|
5470
|
+
const thumbnailTask = (async () => {
|
|
5471
|
+
try {
|
|
5472
|
+
const result = await generateImage({
|
|
5473
|
+
prompt: thumbnailPrompt,
|
|
5474
|
+
options: {
|
|
5475
|
+
width: 1280,
|
|
5476
|
+
height: 720
|
|
5019
5477
|
}
|
|
5478
|
+
});
|
|
5479
|
+
if (result.success && result.data.url) {
|
|
5480
|
+
const thumbPath = join2(options.output, "thumbnail.jpg");
|
|
5481
|
+
await downloadFile3(result.data.url, thumbPath);
|
|
5482
|
+
totalCost += result.data.cost || 0;
|
|
5483
|
+
return thumbPath;
|
|
5484
|
+
}
|
|
5485
|
+
return null;
|
|
5486
|
+
} catch (err) {
|
|
5487
|
+
if (format === "human") {
|
|
5488
|
+
spinner?.stop();
|
|
5489
|
+
warn(`Thumbnail generation failed: ${err.message}`);
|
|
5020
5490
|
spinner?.start();
|
|
5021
5491
|
}
|
|
5022
|
-
|
|
5492
|
+
return null;
|
|
5493
|
+
}
|
|
5494
|
+
})();
|
|
5495
|
+
parallelTasks.push(thumbnailTask);
|
|
5496
|
+
const [musicResult, thumbResult] = await Promise.all(parallelTasks);
|
|
5497
|
+
if (musicResult) {
|
|
5498
|
+
musicInfo = musicResult;
|
|
5499
|
+
totalCost += musicResult.cost || 0;
|
|
5500
|
+
if (format === "human") {
|
|
5501
|
+
spinner?.stop();
|
|
5502
|
+
success(`Music: ${join2(audioDir, "music.mp3")} (${musicResult.duration}s)`);
|
|
5503
|
+
if (musicResult.duration < actualVideoDuration) {
|
|
5504
|
+
warn(`Music duration (${musicResult.duration.toFixed(1)}s) is shorter than video duration (${actualVideoDuration.toFixed(1)}s).`);
|
|
5505
|
+
}
|
|
5506
|
+
spinner?.start();
|
|
5507
|
+
}
|
|
5508
|
+
}
|
|
5509
|
+
if (thumbResult) {
|
|
5510
|
+
thumbnailPath = thumbResult;
|
|
5511
|
+
if (format === "human") {
|
|
5023
5512
|
spinner?.stop();
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
if (spinner && format === "human") spinner?.start();
|
|
5513
|
+
success(`Thumbnail: ${thumbnailPath}`);
|
|
5514
|
+
spinner?.start();
|
|
5027
5515
|
}
|
|
5028
5516
|
}
|
|
5029
5517
|
if (spinner) spinner.text = "Writing manifest...";
|
|
5030
5518
|
const totalDurationInFrames = Math.round(actualVideoDuration * DEFAULT_FPS);
|
|
5031
5519
|
const manifest = {
|
|
5032
5520
|
music: musicInfo,
|
|
5521
|
+
thumbnail: thumbnailPath ? "thumbnail.jpg" : void 0,
|
|
5033
5522
|
images: allImages,
|
|
5034
5523
|
videos: allVideos,
|
|
5035
5524
|
scenes,
|
|
@@ -5117,7 +5606,7 @@ var searchCommand2 = new Command19("search").description("Search for stock video
|
|
|
5117
5606
|
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
5118
5607
|
}
|
|
5119
5608
|
});
|
|
5120
|
-
var initCommand = new Command19("init").description("Create a new Remotion video project from template").argument("<name>", "Project directory name").option("-t, --template <repo>", "GitHub repo (user/repo)", DEFAULT_TEMPLATE).option("--type <type>", "Video type: landscape (16:9) or tiktok (9:16)", "landscape").option("--no-install", "Skip
|
|
5609
|
+
var initCommand = new Command19("init").description("Create a new Remotion video project from template").argument("<name>", "Project directory name").option("-t, --template <repo>", "GitHub repo (user/repo)", DEFAULT_TEMPLATE).option("--type <type>", "Video type: landscape (16:9) or tiktok (9:16)", "landscape").option("--no-install", "Skip npm install").option("-f, --format <format>", "Output format: human, json, quiet", "human").action(async (name, options) => {
|
|
5121
5610
|
const format = options.format;
|
|
5122
5611
|
const spinner = format === "human" ? ora12("Initializing video project...").start() : null;
|
|
5123
5612
|
try {
|
|
@@ -5157,7 +5646,7 @@ var initCommand = new Command19("init").description("Create a new Remotion video
|
|
|
5157
5646
|
if (options.install) {
|
|
5158
5647
|
if (spinner) spinner.text = "Installing dependencies...";
|
|
5159
5648
|
await new Promise((resolvePromise, reject) => {
|
|
5160
|
-
const child = spawn("
|
|
5649
|
+
const child = spawn("npm", ["install"], {
|
|
5161
5650
|
cwd: targetDir,
|
|
5162
5651
|
stdio: "pipe",
|
|
5163
5652
|
shell: true
|
|
@@ -5166,7 +5655,7 @@ var initCommand = new Command19("init").description("Create a new Remotion video
|
|
|
5166
5655
|
if (code === 0) {
|
|
5167
5656
|
resolvePromise();
|
|
5168
5657
|
} else {
|
|
5169
|
-
reject(new Error(`
|
|
5658
|
+
reject(new Error(`npm install failed with code ${code}`));
|
|
5170
5659
|
}
|
|
5171
5660
|
});
|
|
5172
5661
|
child.on("error", reject);
|
|
@@ -5224,14 +5713,14 @@ var initCommand = new Command19("init").description("Create a new Remotion video
|
|
|
5224
5713
|
info("Next steps:");
|
|
5225
5714
|
info(` cd ${name}`);
|
|
5226
5715
|
if (!options.install) {
|
|
5227
|
-
info("
|
|
5716
|
+
info(" npm install");
|
|
5228
5717
|
}
|
|
5229
|
-
info("
|
|
5718
|
+
info(" npm run dev # Preview in Remotion Studio");
|
|
5230
5719
|
info(" cc video create ... # Generate assets to public/");
|
|
5231
5720
|
if (options.type === "tiktok") {
|
|
5232
|
-
info("
|
|
5721
|
+
info(" npx remotion render TikTokVideo out/tiktok.mp4 --props='{...}' # Render TikTok video");
|
|
5233
5722
|
} else {
|
|
5234
|
-
info("
|
|
5723
|
+
info(" npx remotion render YouTubeVideo out/youtube.mp4 --props='{...}' # Render YouTube video");
|
|
5235
5724
|
}
|
|
5236
5725
|
} catch (err) {
|
|
5237
5726
|
spinner?.stop();
|
|
@@ -5281,7 +5770,6 @@ var thumbnailCommand = new Command19("thumbnail").description("Embed a thumbnail
|
|
|
5281
5770
|
if (options.composition) {
|
|
5282
5771
|
if (spinner) spinner.text = `Extracting frame ${frameNum} from ${options.composition}...`;
|
|
5283
5772
|
const args = [
|
|
5284
|
-
"exec",
|
|
5285
5773
|
"remotion",
|
|
5286
5774
|
"still",
|
|
5287
5775
|
options.composition,
|
|
@@ -5289,7 +5777,7 @@ var thumbnailCommand = new Command19("thumbnail").description("Embed a thumbnail
|
|
|
5289
5777
|
`--frame=${frameNum}`
|
|
5290
5778
|
];
|
|
5291
5779
|
try {
|
|
5292
|
-
execSync(`
|
|
5780
|
+
execSync(`npx ${args.join(" ")}`, {
|
|
5293
5781
|
stdio: "pipe",
|
|
5294
5782
|
cwd: process.cwd()
|
|
5295
5783
|
});
|
|
@@ -5378,9 +5866,65 @@ var thumbnailCommand = new Command19("thumbnail").description("Embed a thumbnail
|
|
|
5378
5866
|
});
|
|
5379
5867
|
var videoCommand = new Command19("video").description("Video asset generation commands").addCommand(initCommand).addCommand(createCommand3).addCommand(searchCommand2).addCommand(thumbnailCommand);
|
|
5380
5868
|
|
|
5869
|
+
// src/commands/scrape.ts
|
|
5870
|
+
import { Command as Command20 } from "commander";
|
|
5871
|
+
import ora13 from "ora";
|
|
5872
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
5873
|
+
var scrapeCommand = new Command20("scrape").description("Extract content from a URL").argument("<url>", "URL to scrape").option("-o, --output <path>", "Save content to file").option("-f, --format <format>", "Output format: human, json, quiet", "human").action(async (url, options) => {
|
|
5874
|
+
const format = options.format;
|
|
5875
|
+
const spinner = format === "human" ? ora13("Scraping URL...").start() : null;
|
|
5876
|
+
try {
|
|
5877
|
+
const result = await scrapeUrl(url);
|
|
5878
|
+
spinner?.stop();
|
|
5879
|
+
if (!result.success) {
|
|
5880
|
+
error(result.error || "Failed to scrape URL");
|
|
5881
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
5882
|
+
}
|
|
5883
|
+
const data = result.data;
|
|
5884
|
+
if (options.output) {
|
|
5885
|
+
await writeFile6(options.output, data.content, "utf-8");
|
|
5886
|
+
if (format === "human") {
|
|
5887
|
+
success(`Content saved to: ${options.output}`);
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
if (format === "json") {
|
|
5891
|
+
printJson(data);
|
|
5892
|
+
return;
|
|
5893
|
+
}
|
|
5894
|
+
if (format === "quiet") {
|
|
5895
|
+
console.log(data.content);
|
|
5896
|
+
return;
|
|
5897
|
+
}
|
|
5898
|
+
if (data.title) {
|
|
5899
|
+
console.log();
|
|
5900
|
+
console.log(`Title: ${data.title}`);
|
|
5901
|
+
}
|
|
5902
|
+
if (data.metadata?.description) {
|
|
5903
|
+
console.log(`Description: ${data.metadata.description}`);
|
|
5904
|
+
}
|
|
5905
|
+
console.log(`URL: ${data.url}`);
|
|
5906
|
+
console.log(`Tokens: ~${data.metadata?.tokenUsage?.toLocaleString() || "unknown"}`);
|
|
5907
|
+
if (data.warning) {
|
|
5908
|
+
warn(data.warning);
|
|
5909
|
+
}
|
|
5910
|
+
if (!options.output) {
|
|
5911
|
+
console.log();
|
|
5912
|
+
console.log("--- Content ---");
|
|
5913
|
+
console.log(data.content);
|
|
5914
|
+
}
|
|
5915
|
+
if (data.cost && data.cost > 0) {
|
|
5916
|
+
info(`Cost: $${data.cost.toFixed(6)}`);
|
|
5917
|
+
}
|
|
5918
|
+
} catch (err) {
|
|
5919
|
+
spinner?.stop();
|
|
5920
|
+
error(err instanceof Error ? err.message : "Unknown error");
|
|
5921
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
5922
|
+
}
|
|
5923
|
+
});
|
|
5924
|
+
|
|
5381
5925
|
// src/index.ts
|
|
5382
|
-
var VERSION = "0.1.
|
|
5383
|
-
var program = new
|
|
5926
|
+
var VERSION = "0.1.14";
|
|
5927
|
+
var program = new Command21();
|
|
5384
5928
|
var cmdName = brand.commands[0];
|
|
5385
5929
|
program.name(cmdName).description(brand.description).version(VERSION, "-v, --version", "Show version number").option("--debug", "Enable debug logging").option("--no-color", "Disable colored output").configureOutput({
|
|
5386
5930
|
outputError: (str, write) => {
|
|
@@ -5405,6 +5949,7 @@ program.addCommand(musicCommand);
|
|
|
5405
5949
|
program.addCommand(mixAudioCommand);
|
|
5406
5950
|
program.addCommand(imageCommand);
|
|
5407
5951
|
program.addCommand(videoCommand);
|
|
5952
|
+
program.addCommand(scrapeCommand);
|
|
5408
5953
|
var deriveCommand = buildDeriveCommand();
|
|
5409
5954
|
if (deriveCommand.commands.length > 0) {
|
|
5410
5955
|
program.addCommand(deriveCommand);
|