Text to Video with Custom Subtitle Style
This example demonstrates how to create a video with fully customized subtitle styles defined inline. Instead of using saved styles, you can specify all styling properties directly in the API request.
Overview
This example covers:
- Getting an access token
- Creating custom subtitle styles with inline configuration
- Customizing fonts, colors, positions, and animations
- Applying styles at video level and scene level
- Understanding all available style properties
- Monitoring job status and retrieving the final video
Node.js Example
Prerequisites
npm install axiosComplete Code
import axios from "axios";
const API_BASE_URL = "https://api.pictory.ai/pictoryapis";
const CLIENT_ID = "YOUR_CLIENT_ID";
const CLIENT_SECRET = "YOUR_CLIENT_SECRET";
const STORY_TEXT = "AI is poised to significantly impact educators and course creators on social media.";
async function createTextToVideoWithCustomSubtitleStyle() {
try {
// Step 1: Get Access Token
console.log("Step 1: Getting access token...");
const tokenResponse = await axios.post(
`${API_BASE_URL}/v1/oauth2/token`,
{
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
},
{
headers: {
"Content-Type": "application/json",
},
}
);
const accessToken = tokenResponse.data.access_token;
console.log("Access token obtained successfully");
console.log("Token expires in:", tokenResponse.data.expires_in, "seconds\n");
// Step 2: Create Video with Custom Subtitle Style
console.log("Step 2: Creating video with custom subtitle style...");
const storyboardResponse = await axios.post(
`${API_BASE_URL}/v2/video/storyboard/render`,
{
videoName: "text_to_video_custom_subtitle",
// Video-level custom subtitle style
subtitleStyle: {
fontFamily: "Poppins",
fontSize: 48,
color: "rgba(255, 255, 255, 1)", // White text
backgroundColor: "rgba(0, 0, 0, 0.7)", // Semi-transparent black background
keywordColor: "rgba(255, 215, 0, 1)", // Gold color for keywords
shadowColor: "rgba(0, 0, 0, 0.8)",
shadowWidth: "2%",
position: "bottom-center",
alignment: "center",
decorations: ["bold"],
case: "capitalize",
paragraphWidth: "80%",
showBoxBackground: true,
animations: [
{
name: "fade",
type: "entry",
speed: "medium",
},
{
name: "fade",
type: "exit",
speed: "fast",
},
],
},
scenes: [
{
story: STORY_TEXT,
createSceneOnNewLine: false,
createSceneOnEndOfSentence: false,
},
],
},
{
headers: {
"Content-Type": "application/json",
Authorization: accessToken,
},
}
);
const renderJobId = storyboardResponse.data.data.jobId;
console.log("Video with custom subtitle style render job created");
console.log("Job ID:", renderJobId, "\n");
// Step 3: Monitor Job Status
console.log("Step 3: Monitoring job status...");
let jobCompleted = false;
let jobResult = null;
while (!jobCompleted) {
const jobStatusResponse = await axios.get(`${API_BASE_URL}/v1/jobs/${renderJobId}`, {
headers: {
Authorization: accessToken,
},
});
const status = jobStatusResponse.data.data.status;
console.log("Current status:", status);
if (status === "completed") {
jobCompleted = true;
jobResult = jobStatusResponse.data;
console.log("\nVideo with custom subtitle style created successfully!");
console.log("Video URL:", jobResult.data.videoUrl);
} else if (status === "failed") {
throw new Error("Job failed: " + JSON.stringify(jobStatusResponse.data));
} else {
// Wait 5 seconds before checking again
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
return jobResult;
} catch (error) {
console.error("Error:", error.response?.data || error.message);
throw error;
}
}
// Run the function
createTextToVideoWithCustomSubtitleStyle();Python Example
Prerequisites
pip install requestsComplete Code
import requests
import time
import json
API_BASE_URL = 'https://api.pictory.ai/pictoryapis'
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
STORY_TEXT = "AI is poised to significantly impact educators and course creators on social media."
def create_text_to_video_with_custom_subtitle_style():
try:
# Step 1: Get Access Token
print('Step 1: Getting access token...')
token_response = requests.post(
f'{API_BASE_URL}/v1/oauth2/token',
json={
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET
},
headers={
'Content-Type': 'application/json'
}
)
token_response.raise_for_status()
access_token = token_response.json()['access_token']
print('Access token obtained successfully')
print(f"Token expires in: {token_response.json()['expires_in']} seconds\n")
# Step 2: Create Video with Custom Subtitle Style
print('Step 2: Creating video with custom subtitle style...')
storyboard_response = requests.post(
f'{API_BASE_URL}/v2/video/storyboard/render',
json={
'videoName': 'text_to_video_custom_subtitle',
# Video-level custom subtitle style
'subtitleStyle': {
'fontFamily': 'Poppins',
'fontSize': 48,
'color': 'rgba(255, 255, 255, 1)', # White text
'backgroundColor': 'rgba(0, 0, 0, 0.7)', # Semi-transparent black background
'keywordColor': 'rgba(255, 215, 0, 1)', # Gold color for keywords
'shadowColor': 'rgba(0, 0, 0, 0.8)',
'shadowWidth': '2%',
'position': 'bottom-center',
'alignment': 'center',
'decorations': ['bold'],
'case': 'capitalize',
'paragraphWidth': '80%',
'showBoxBackground': True,
'animations': [
{
'name': 'fade',
'type': 'entry',
'speed': 'medium'
},
{
'name': 'fade',
'type': 'exit',
'speed': 'fast'
}
]
},
'scenes': [
{
'story': STORY_TEXT,
'createSceneOnNewLine': False,
'createSceneOnEndOfSentence': False
}
]
},
headers={
'Content-Type': 'application/json',
'Authorization': access_token
}
)
storyboard_response.raise_for_status()
render_job_id = storyboard_response.json()['data']['jobId']
print('Video with custom subtitle style render job created')
print(f'Job ID: {render_job_id}\n')
# Step 3: Monitor Job Status
print('Step 3: Monitoring job status...')
job_completed = False
job_result = None
while not job_completed:
job_status_response = requests.get(
f'{API_BASE_URL}/v1/jobs/{render_job_id}',
headers={
'Authorization': access_token
}
)
job_status_response.raise_for_status()
status = job_status_response.json()['data']['status']
print(f'Current status: {status}')
if status == 'completed':
job_completed = True
job_result = job_status_response.json()
print('\nVideo with custom subtitle style created successfully!')
print(f"Video URL: {job_result['data']['videoUrl']}")
elif status == 'failed':
raise Exception(f"Job failed: {json.dumps(job_status_response.json())}")
else:
# Wait 5 seconds before checking again
time.sleep(5)
return job_result
except requests.exceptions.RequestException as error:
print(f'Error: {error}')
if hasattr(error, 'response') and error.response is not None:
print(f'Response: {error.response.text}')
raise
# Run the function
if __name__ == '__main__':
create_text_to_video_with_custom_subtitle_style()Available Style Properties
Font Properties
- fontFamily: Font name (e.g., "Poppins", "Arial", "Roboto")
- fontUrl (optional): Custom font URL if using a non-standard font
- fontSize: Font size in pixels (e.g., 48, 64)
Color Properties
All colors must be in RGBA format:
- color: Text color (e.g., "rgba(255, 255, 255, 1)")
- backgroundColor: Background color behind text (e.g., "rgba(0, 0, 0, 0.7)")
- keywordColor: Color for highlighted keywords (e.g., "rgba(255, 215, 0, 1)")
- shadowColor: Text shadow color (e.g., "rgba(0, 0, 0, 0.8)")
Position and Layout
- position: Text position on screen
- Options: "top-left", "top-center", "top-right", "center-left", "center-center", "center-right", "bottom-left", "bottom-center", "bottom-right"
- alignment: Text alignment
- Options: "left", "center", "right"
- paragraphWidth: Width as percentage (e.g., "80%")
- shadowWidth: Shadow width as percentage (e.g., "2%")
Text Styling
- decorations: Array of text decorations
- Options: "bold", "underline", "italics", "linethrough"
- case: Text casing
- Options: "uppercase", "lowercase", "capitalize", "smallcapitalize"
Background and Display
- showBoxBackground: Boolean - Show/hide background box
- showBullet: Boolean - Show/hide bullet points
- bulletSize: Bullet size in pixels
- bulletFillColor: Bullet color in RGBA format
Animations
- animations: Array of animation objects (max 2: one entry, one exit)
- name: Animation name
- Options: "none", "fade", "drift", "wipe", "text reveal", "elastic", "typewriter", "blur", "bulletin"
- type: "entry" or "exit"
- speed: "slow", "medium", "fast", or "custom"
- customSpeedValue: Number (required if speed is "custom", min 0.5)
- direction: "up", "down", "left", "right" (for applicable animations)
- writingStyle: "character", "word", "line", "paragraph" (for text reveal animations)
- name: Animation name
RGBA Color Format
Always use RGBA format for colors:
rgba(R, G, B, A)where:- R, G, B: 0-255 (red, green, blue)
- A: 0-1 (alpha/transparency, where 0 is fully transparent, 1 is fully opaque)
Examples:
- White:
rgba(255, 255, 255, 1) - Black:
rgba(0, 0, 0, 1) - Semi-transparent black:
rgba(0, 0, 0, 0.7) - Gold:
rgba(255, 215, 0, 1) - Red:
rgba(255, 0, 0, 1)
Scene-Level Custom Styles
You can also apply custom styles at the scene level:
scenes: [
{
story: "Scene text",
subtitleStyle: {
fontFamily: "Arial",
fontSize: 36,
color: "rgba(255, 255, 255, 1)",
position: "bottom-center",
},
},
];Use Cases
- Create unique, branded subtitle styles without saving them
- Experiment with different styles quickly
- Generate videos with dynamic styling based on content
- A/B test different subtitle appearances
- Create one-off videos with custom styling
Response
The API returns a job ID for monitoring the video creation progress. Once completed, you'll receive a video URL with your custom subtitle styling applied.
Notes
- Replace
YOUR_CLIENT_IDandYOUR_CLIENT_SECRETwith your actual API credentials - All color values must be in RGBA format as specified
- Percentage values must be strings with "%" symbol (e.g., "80%")
- Maximum 2 animations per subtitle style (one entry, one exit)
- Scene-level styles override video-level styles
Updated about 15 hours ago
