AI Video Generation with Veo and TypeScript: A Developer's Guide
The line between static content and dynamic video is blurring. With Google's Veo 3.1 model and NeuroLink, you can now generate professional 8-second video clips with synchronized audio from a single image and text prompt—all through a clean TypeScript API.
In this guide, I'll walk you through building a video generation workflow that transforms static images into compelling video content. Whether you're creating product showcases, social media content, or marketing materials, this approach eliminates the need for expensive video production while maintaining quality.
What You'll Build
By the end of this guide, you'll have:
- A working video generation pipeline using NeuroLink and Veo 3.1
- Understanding of text-to-video and image-to-video workflows
- Production-ready patterns for batch processing and error handling
- Cost optimization strategies for different use cases
Prerequisites
Before we start, ensure you have:
# Node.js 18+ and pnpm/npm
node --version # Should be >= 18
# NeuroLink SDK
npm install @juspay/neurolink
# Google Cloud credentials with Vertex AI access
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json
You'll also need a Google Cloud project with:
- Vertex AI API enabled
- Billing configured
- Service account with
aiplatform.userrole
Understanding the Veo 3.1 Model
Veo 3.1 is Google's state-of-the-art video generation model available through Vertex AI. Here's what it offers:
| Feature | Specification |
|---|---|
| Duration | 4, 6, or 8 seconds per clip |
| Resolution | 720p or 1080p |
| Aspect Ratios | 16:9 (landscape) or 9:16 (portrait) |
| Audio | Auto-generated, synchronized with video |
| Input | Image + text prompt (required) |
| Processing Time | 30-120 seconds depending on resolution |
Key Limitation: Veo requires an input image—text-only prompts aren't supported. The workflow is image-to-video, not pure text-to-video.
Basic Video Generation
Let's start with a simple example that transforms a product image into a showcase video:
import { NeuroLink } from "@juspay/neurolink";
import { readFileSync, writeFileSync } from "fs";
const neurolink = new NeuroLink();
async function generateProductVideo() {
const result = await neurolink.generate({
input: {
text: "Smooth 360-degree rotation with soft studio lighting, camera slowly reveals product details",
images: [readFileSync("./product-hero.jpg")],
},
provider: "vertex",
model: "veo-3.1",
output: {
mode: "video",
video: {
resolution: "1080p",
length: 8,
aspectRatio: "16:9",
audio: true,
},
},
});
if (result.video) {
writeFileSync("product-showcase.mp4", result.video.data);
console.log(`Generated ${result.video.metadata?.duration}s video`);
console.log(`Resolution: ${result.video.metadata?.dimensions?.width}x${result.video.metadata?.dimensions?.height}`);
}
}
generateProductVideo();
This code:
- Loads your input image
- Sends it to Veo 3.1 with a descriptive motion prompt
- Receives an MP4 buffer with metadata
- Saves the video to disk
Advanced Workflow: AI-Directed Video Generation
Here's where it gets interesting. You can chain NeuroLink's capabilities to create an AI-directed video pipeline:
import { NeuroLink } from "@juspay/neurolink";
import { readFile, writeFile } from "fs/promises";
const neurolink = new NeuroLink();
async function aiDirectedVideo(imagePath: string, outputPath: string) {
// Step 1: Analyze the image and generate a video concept
const analysis = await neurolink.generate({
input: {
text: `Analyze this image and suggest a compelling 8-second video concept.
Describe camera movement, lighting changes, and visual effects.
Be specific about motion and timing.`,
images: [await readFile(imagePath)],
},
provider: "vertex",
model: "gemini-2.5-flash",
});
console.log("AI Concept:", analysis.content);
// Step 2: Use the AI-generated concept for video generation
const videoResult = await neurolink.generate({
input: {
text: analysis.content, // AI-generated prompt
images: [await readFile(imagePath)],
},
provider: "vertex",
model: "veo-3.1",
output: {
mode: "video",
video: {
resolution: "1080p",
length: 8,
aspectRatio: "16:9",
},
},
});
if (videoResult.video) {
await writeFile(outputPath, videoResult.video.data);
console.log("AI-directed video generated successfully!");
}
}
// Usage
await aiDirectedVideo("./input.jpg", "./ai-video.mp4");
This two-step approach lets the AI analyze visual elements and craft optimal motion directions, resulting in more compelling videos than generic prompts.
Batch Processing Pipeline
For content creators managing multiple assets, here's a production-ready batch pipeline with concurrency control:
import { NeuroLink } from "@juspay/neurolink";
import { readdir, readFile, writeFile, mkdir } from "fs/promises";
import path from "path";
import pLimit from "p-limit";
interface PipelineConfig {
inputDir: string;
outputDir: string;
prompts: Record<string, string>; // filename pattern → prompt
defaultPrompt: string;
resolution: "720p" | "1080p";
aspectRatio: "9:16" | "16:9";
concurrency: number;
}
async function batchVideoPipeline(config: PipelineConfig) {
const neurolink = new NeuroLink();
const limit = pLimit(config.concurrency); // Rate limiting for Vertex AI quotas
await mkdir(config.outputDir, { recursive: true });
const files = await readdir(config.inputDir);
const imageFiles = files.filter(f => /\.(jpg|jpeg|png|webp)$/i.test(f));
const results = await Promise.all(
imageFiles.map(imageFile =>
limit(async () => {
// Find matching prompt or use default
const prompt = Object.entries(config.prompts).find(([pattern]) =>
imageFile.startsWith(pattern)
)?.[1] || config.defaultPrompt;
try {
const imageBuffer = await readFile(path.join(config.inputDir, imageFile));
const result = await neurolink.generate({
input: { text: prompt, images: [imageBuffer] },
provider: "vertex",
model: "veo-3.1",
output: {
mode: "video",
video: {
resolution: config.resolution,
aspectRatio: config.aspectRatio,
length: 8,
},
},
});
if (result.video) {
const outputPath = path.join(
config.outputDir,
`${path.basename(imageFile, path.extname(imageFile))}.mp4`
);
await writeFile(outputPath, result.video.data);
return { input: imageFile, output: outputPath, success: true };
}
} catch (error) {
return {
input: imageFile,
success: false,
error: error instanceof Error ? error.message : "Unknown error"
};
}
})
)
);
return results;
}
// Usage
const results = await batchVideoPipeline({
inputDir: "./product-images",
outputDir: "./product-videos",
prompts: {
"product-": "Elegant rotation with soft lighting",
"hero-": "Dramatic zoom with cinematic depth",
"lifestyle-": "Natural ambient movement",
},
defaultPrompt: "Smooth camera movement showcasing the subject",
resolution: "1080p",
aspectRatio: "16:9",
concurrency: 3, // Stay within Vertex AI rate limits
});
console.table(results);
CLI-First Workflow
NeuroLink's CLI supports video generation directly from the command line:
# Basic generation
npx @juspay/neurolink generate "Smooth camera pan across the product" \
--image ./product.jpg \
--videoOutput ./output.mp4
# Full options
npx @juspay/neurolink generate "Cinematic zoom with dramatic lighting" \
--image ./hero.jpg \
--provider vertex \
--model veo-3.1 \
--videoResolution 1080p \
--videoLength 8 \
--videoAspectRatio 16:9 \
--videoAudio true \
--videoOutput ./hero-video.mp4
# Portrait format for social media
npx @juspay/neurolink generate "Vertical pan revealing product details" \
--image ./story.jpg \
--videoAspectRatio 9:16 \
--videoLength 6 \
--videoOutput ./story-video.mp4
Cost Optimization
Video generation costs scale with resolution and duration. Here's a practical breakdown:
| Resolution | Duration | Cost | Best For |
|---|---|---|---|
| 720p | 4s | ~$1.60 | Quick previews, drafts |
| 720p | 8s | ~$3.20 | Social media content |
| 1080p | 6s | ~$2.00 | Marketing materials |
| 1080p | 8s | ~$4.00 | Professional productions |
Optimization Tips:
- Use 720p for iteration: Start with lower resolution for proof-of-concept
- Match aspect ratio to platform: 9:16 for Instagram Reels/TikTok, 16:9 for YouTube
- Batch during off-peak: Vertex AI quotas reset periodically
- Implement smart retries: Use exponential backoff for rate limits
Error Handling and Resilience
Production video generation needs robust error handling:
import { NeuroLink, NeuroLinkError } from "@juspay/neurolink";
async function generateVideoWithRetry(imagePath: string, prompt: string, maxRetries = 3) {
const neurolink = new NeuroLink();
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await neurolink.generate({
input: {
text: prompt,
images: [await readFile(imagePath)],
},
provider: "vertex",
model: "veo-3.1",
output: { mode: "video", video: { resolution: "720p", length: 8 } },
timeout: 120000, // Video generation takes time
});
return result.video;
} catch (error) {
if (error instanceof NeuroLinkError) {
// Don't retry configuration/permission errors
if (error.category === "configuration" || error.category === "permission") {
throw error;
}
// Rate limit: exponential backoff
if (error.code.includes("RATE_LIMIT")) {
const waitTime = Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Waiting ${waitTime / 1000}s...`);
await new Promise(r => setTimeout(r, waitTime));
continue;
}
// Network errors: retry with fixed delay
if (error.category === "network" && error.retriable) {
await new Promise(r => setTimeout(r, 2000));
continue;
}
}
throw error;
}
}
throw new Error("Max retries exceeded");
}
Real-World Use Cases
E-commerce Product Videos
Transform static product photos into dynamic showcase videos:
const ecommercePrompt = `
Smooth 360-degree rotation revealing all product angles.
Soft studio lighting with subtle reflections.
Camera slowly zooms in on key features.
Professional product photography style.
`;
Social Media Content
Generate platform-optimized videos:
// Instagram Reels / TikTok
const socialConfig = {
resolution: "720p" as const,
aspectRatio: "9:16" as const,
length: 6 as const, // Snappy, engaging
};
Marketing Hero Videos
Create cinematic landing page content:
const heroConfig = {
resolution: "1080p" as const,
aspectRatio: "16:9" as const,
length: 8 as const,
};
Limitations and Workarounds
| Limitation | Workaround |
|---|---|
| Max 8 seconds per clip | Chain multiple videos with Director Mode |
| Requires input image | Generate image first with Gemini, then use as Veo input |
| No custom audio | Audio is auto-generated; use external tools for custom sound |
| Vertex AI only | No alternative providers currently available |
| 10 req/min rate limit | Implement request queuing and batching |
Next Steps
You've learned the fundamentals of AI video generation with Veo and NeuroLink. To go deeper:
- Explore Director Mode: Chain multiple video segments with AI-generated transitions
- Add Image Generation: Use Gemini to create input images, then animate them with Veo
- Build a Web Interface: Wrap the SDK in a Next.js or SvelteKit app for team collaboration
- Integrate with Your CMS: Automatically generate videos when products are added
The intersection of static and dynamic content is where the most engaging media lives. With NeuroLink and Veo, you're equipped to build at that intersection.
NeuroLink — The Universal AI SDK for TypeScript
- GitHub: github.com/juspay/neurolink
- Install:
npm install @juspay/neurolink - Docs: docs.neurolink.ink
- Blog: blog.neurolink.ink — 150+ technical articles
Top comments (0)