Overview

Every Bluma workspace requires a template.config.ts file that defines how your video template works. This file configures:
  • Which AI services your template needs (script generation, voice, images, etc.)
  • How those services should be configured
  • How to transform service results into Remotion props
  • Video output settings (duration, resolution, fps)
Your template.config.ts must pass validation before your workspace can render videos. Common errors are listed at the bottom of this page.

Basic Structure

import { StandardTemplateConfig } from '../types/standardTemplateConfig';

export const templateConfig: StandardTemplateConfig = {
  // Metadata
  id: 'my-template',
  name: 'My Template',
  description: 'Description of what this template does',

  // Required services
  requiredServices: {
    scriptGeneration: true,
    voiceGeneration: true,
    imageGeneration: false,
    // ... other services
  },

  // Service-specific configs (required when service is enabled)
  scriptConfig: { /* ... */ },
  voiceConfig: { /* ... */ },

  // Remotion settings
  componentName: 'MyComposition',
  compositionId: 'MyComposition',

  // Transform function
  transformToRemotionProps: (results) => ({
    // Map service results to Remotion props
  }),
};

Required Services

The requiredServices object specifies which AI services your template uses:
requiredServices: {
  // Content generation
  scriptGeneration: boolean,       // AI script/dialogue generation
  textGeneration: boolean,         // General text generation
  voiceGeneration: boolean,        // Text-to-speech

  // Image services
  imagePromptGeneration: boolean,  // Generate prompts for images
  imageGeneration: boolean,        // Generate images from prompts
  bulkImageGeneration: boolean,    // Generate multiple images
  gifGeneration: boolean,          // Generate/search GIFs

  // Video services
  frameExtraction: boolean,        // Extract frames from video
  backgroundProcessing: boolean,   // Process background videos
  ugcVideoGeneration: boolean,     // Generate UGC-style videos
  imageToVideoGeneration: boolean, // Animate images to video

  // Audio services
  captionGeneration: boolean,      // Generate captions/subtitles

  // Asset retrieval
  assetCollectionRetrieval: boolean, // Fetch from asset collections

  // Final render
  remotionRender: boolean,         // Remotion video render
}
When you enable a service, you must provide its corresponding config. For example, if frameExtraction: true, you must include frameExtractionConfig.

Service-Specific Configs

frameExtractionConfig

Required when: requiredServices.frameExtraction: true Extracts frames from source videos for use in compositions.
frameExtractionConfig: {
  // Extract every Nth frame (e.g., 30 = one frame per second at 30fps)
  everyNthFrame: 30,

  // Total frames to extract
  // - number: exact count
  // - "script-based": derive from script line count
  totalFramesToExtract: 10,  // or "script-based"

  // Optional: offset frame extraction (e.g., 15 = extract mid-slide frames)
  frameOffset: 15,
}

scriptConfig

Required when: requiredServices.scriptGeneration: true
scriptConfig: {
  // AI model to use
  model: 'gemini' | 'claude' | 'gpt-4',

  // System prompt for the AI
  systemPrompt: 'You are a creative scriptwriter...',

  // How to format the output
  outputFormat: 'json' | 'text',

  // JSON schema for structured output (if outputFormat: 'json')
  outputSchema: {
    type: 'object',
    properties: {
      lines: { type: 'array', items: { type: 'string' } }
    }
  },

  // Temperature for generation (0-2, lower = more deterministic)
  temperature: 0.7,
}

voiceConfig

Required when: requiredServices.voiceGeneration: true
voiceConfig: {
  // Voice provider
  provider: 'elevenlabs' | 'aws-polly',

  // Voice ID or name
  voiceId: 'voice_id_here',

  // Optional settings
  speed: 1.0,        // Playback speed multiplier
  stability: 0.5,    // Voice consistency (ElevenLabs)
  similarity: 0.75,  // Voice matching (ElevenLabs)
}

imageConfigs

Required when: requiredServices.imageGeneration: true or requiredServices.bulkImageGeneration: true
imageConfigs: [
  {
    id: 'background',
    provider: 'dalle' | 'midjourney' | 'stable-diffusion',
    width: 1920,
    height: 1080,
    style: 'photorealistic',
  },
  {
    id: 'character',
    provider: 'dalle',
    width: 512,
    height: 512,
    style: 'cartoon',
  }
]

backgroundConfig

Required when: requiredServices.backgroundProcessing: true
backgroundConfig: {
  // Type of background
  type: 'video' | 'image' | 'color',

  // For video backgrounds
  source: 'asset-pool' | 'upload' | 'generate',
  assetPoolId: 'pool_id_here',

  // Processing options
  blur: 0,           // Blur amount (0-20)
  darken: 0.3,       // Darken overlay (0-1)
  loop: true,        // Loop video background
}

Duration Configuration

Control video length with the durationConfig:
durationConfig: {
  // Duration strategy
  mode: 'fixed' | 'match-audio' | 'slide-based' | 'dynamic',

  // For fixed mode
  defaultDuration: 30,  // seconds

  // For slide-based mode
  framesPerSlide: 90,   // frames (3 seconds at 30fps)

  // Constraints
  minimumDuration: 15,  // seconds
  maximumDuration: 120, // seconds
  padding: 1,           // extra seconds at end
}
ModeDescription
fixedAlways use defaultDuration
match-audioMatch the voice-over length
slide-basedCalculate from number of slides
dynamicCalculated in transformToRemotionProps

Transform Function

The transformToRemotionProps function converts service results into Remotion props:
transformToRemotionProps: (results, inputs) => {
  // results contains outputs from all services:
  // - results.script (from scriptGeneration)
  // - results.voice (from voiceGeneration)
  // - results.images (from imageGeneration)
  // - results.frames (from frameExtraction)
  // etc.

  return {
    // Return props that match your Remotion composition's schema
    script: results.script.lines,
    audioUrl: results.voice.audioUrl,
    images: results.images.map(img => img.url),
    durationInFrames: results.voice.durationInFrames,
  };
}

Common Validation Errors

Problem: You set requiredServices.frameExtraction: true but didn’t provide the config.Solution: Add the frameExtractionConfig object:
requiredServices: {
  frameExtraction: true,
  // ...
},
frameExtractionConfig: {
  everyNthFrame: 30,
  totalFramesToExtract: 10,
},
Problem: You enabled script generation but didn’t configure it.Solution: Add scriptConfig with at least model and systemPrompt:
scriptConfig: {
  model: 'gemini',
  systemPrompt: 'Your prompt here...',
  outputFormat: 'json',
},
Problem: Voice generation is enabled without configuration.Solution: Add voiceConfig:
voiceConfig: {
  provider: 'elevenlabs',
  voiceId: 'your_voice_id',
},
Problem: The transform function is missing or not a function.Solution: Add the transform function:
transformToRemotionProps: (results) => ({
  // Map results to your composition props
}),
Problem: Missing Remotion component reference.Solution: Add both fields:
componentName: 'MyComposition',
compositionId: 'MyComposition',

Complete Example

Here’s a minimal working template config:
import { StandardTemplateConfig } from '../types/standardTemplateConfig';

export const templateConfig: StandardTemplateConfig = {
  // Metadata
  id: 'simple-slideshow',
  name: 'Simple Slideshow',
  description: 'A basic slideshow with voiceover',
  category: 'slideshow',
  version: '1.0.0',

  // Services needed
  requiredServices: {
    scriptGeneration: true,
    voiceGeneration: true,
    imageGeneration: false,
    bulkImageGeneration: false,
    gifGeneration: false,
    frameExtraction: false,
    captionGeneration: false,
    backgroundProcessing: true,
    assetCollectionRetrieval: false,
    ugcVideoGeneration: false,
    remotionRender: true,
  },

  // Script generation config
  scriptConfig: {
    model: 'gemini',
    systemPrompt: 'Create a 5-slide script for a slideshow about the given topic.',
    outputFormat: 'json',
    temperature: 0.7,
  },

  // Voice config
  voiceConfig: {
    provider: 'elevenlabs',
    voiceId: 'pNInz6obpgDQGcFmaJgB', // Adam
    speed: 1.0,
  },

  // Background config
  backgroundConfig: {
    type: 'video',
    source: 'asset-pool',
    assetPoolId: 'backgrounds',
    loop: true,
    darken: 0.4,
  },

  // Duration
  durationConfig: {
    mode: 'match-audio',
    minimumDuration: 15,
    maximumDuration: 60,
    padding: 1,
  },

  // Remotion
  componentName: 'SimpleSlideshow',
  compositionId: 'SimpleSlideshow',
  defaultFps: 30,

  // Transform results to props
  transformToRemotionProps: (results) => ({
    slides: results.script.slides,
    audioUrl: results.voice.audioUrl,
    backgroundUrl: results.background?.url,
    durationInFrames: results.voice.durationInFrames || 900,
  }),
};

export default templateConfig;

Need Help?