Templates
Templates are the core building block of Peako Studio. A template defines the structure of your video — tracks, blocks, timing, and canvas settings — without any actual content. Content is filled in at render time.
Template Structure
A template contains:
- Composition — canvas size, fps, duration, background
- Tracks — layers (video, audio, text, sticker)
- Blocks — fillable placeholders within each track
- Transitions — effects between adjacent blocks
- Effects — visual filters on individual blocks
Block Types
| Type | Description | Filled with |
|---|---|---|
video | Video content | src_url or upload_url |
image | Image content | src_url or upload_url |
audio | Audio track | src_url or upload_url |
text | Static text | text or rich_text |
subtitle | Timed captions | captions, auto_transcribe, or text |
transition | Visual transition between blocks | (no fill — auto-applied) |
Duration Modes
| Mode | Behavior |
|---|---|
locked | Block uses its template-defined duration. Asset is trimmed or padded to fit. |
trim_to_asset | Block duration stretches to match the actual asset length. |
stretch_to_slot | Asset is stretched/compressed to fill the block's defined duration. |
Transform Coordinates
All position values use normalized coordinates (0.0–1.0):
x: 0.0, y: 0.0= top-left cornerx: 0.5, y: 0.5= centerwidth: 1.0, height: 1.0= full canvasx: 0.1, y: 0.8, width: 0.8, height: 0.2= 80% wide bar near the bottom
Create Template
POST /api/templates
Create a new template with a composition structure and named blocks.
Headers:
X-API-Key: <your-api-key>(required)Content-Type: application/json
Request Body:
{
"name": "Social Media Short",
"description": "9:16 vertical video with subtitles",
"thumbnail": "https://peako.shin0x.space/assets/thumb-uuid.jpg",
"composition": {
"fps": 30,
"durationSec": 15,
"size": {
"width": 1080,
"height": 1920
},
"background": {
"type": "color",
"value": "#000000"
},
"tracks": [
{
"id": "track-video",
"type": "video",
"name": "Main Video",
"isBaseLayer": true,
"zIndex": 0,
"items": [
{
"itemType": "block",
"blockId": "hero-video",
"type": "video",
"label": "Hero Video",
"required": true,
"durationMode": "locked",
"startSec": 0,
"durationSec": 15,
"transform": {
"x": 0,
"y": 0,
"width": 1,
"height": 1,
"opacity": 1
}
}
]
},
{
"id": "track-subtitles",
"type": "text",
"name": "Subtitles",
"zIndex": 2,
"items": [
{
"itemType": "block",
"blockId": "subtitle-main",
"type": "subtitle",
"label": "Auto-Generated Subtitles",
"required": false,
"durationMode": "locked",
"startSec": 0,
"durationSec": 15,
"transform": {
"x": 0.05,
"y": 0.75,
"width": 0.9,
"height": 0.2
}
}
]
}
],
"transitions": [],
"effects": [],
"audioMix": {
"masterVolume": 1.0
}
}
}
Composition Fields:
| Field | Type | Required | Description |
|---|---|---|---|
fps | number | ✓ | Frames per second (1–120) |
durationSec | number | ✓ | Total duration in seconds (> 0) |
size.width | number | ✓ | Canvas width in pixels |
size.height | number | ✓ | Canvas height in pixels |
background.type | string | ✓ | "color" or "image" |
background.value | string | ✓ | Hex color (e.g. "#000000") or image URL |
tracks | array | ✓ | Array of track objects (max 20) |
transitions | array | ✗ | Transition definitions |
effects | array | ✗ | Global effect definitions |
audioMix.masterVolume | number | ✗ | Master volume (0.0–1.0, default 1.0) |
Track Object Fields:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Unique track ID |
type | string | ✓ | "video", "audio", "text", "sticker" |
name | string | ✓ | Display name |
isBaseLayer | boolean | ✗ | If true, this is the full-canvas base layer |
zIndex | number | ✗ | Render order (0 = bottom) |
state.muted | boolean | ✗ | Mute audio on this track |
state.hidden | boolean | ✗ | Hide this track in render |
items | array | ✓ | Array of block items |
Block Item Fields:
| Field | Type | Required | Description |
|---|---|---|---|
itemType | string | ✓ | Must be "block" |
blockId | string | ✓ | Unique ID for this block — referenced during render |
type | string | ✓ | "video", "image", "audio", "text", "subtitle" |
label | string | ✓ | Human-readable label |
required | boolean | ✓ | If true, must be filled at render time |
durationMode | string | ✓ | "locked", "trim_to_asset", or "stretch_to_slot" |
startSec | number | ✓ | Start time in the timeline (≥ 0) |
durationSec | number | ✓ | Duration in the timeline (> 0) |
transform.x | number | ✓ | Horizontal position (0.0–1.0) |
transform.y | number | ✓ | Vertical position (0.0–1.0) |
transform.width | number | ✓ | Width as fraction of canvas (0.0–1.0) |
transform.height | number | ✓ | Height as fraction of canvas (0.0–1.0) |
transform.opacity | number | ✗ | Opacity (0.0–1.0, default 1.0) |
transform.rotation | number | ✗ | Rotation in degrees |
effects | array | ✗ | Effects applied to this block |
Response (201 — Created):
{
"id": "template-550e8400-e29b-41d4-a716-446655440000",
"name": "Social Media Short",
"description": "9:16 vertical video with subtitles",
"thumbnail": "https://peako.shin0x.space/assets/thumb-uuid.jpg",
"variableSchema": {},
"createdAt": 1709767500000
}
Error Codes:
400— Invalid composition structure or validation failed401— Missing or invalid API key
Get Template
GET /api/templates/:id
Retrieve the full template including composition structure and blockSchema.
Path Parameters:
id— template ID
Headers:
X-API-Key: <your-api-key>(required)
Response:
{
"id": "template-uuid",
"name": "Social Media Short",
"description": "9:16 vertical video with subtitles",
"thumbnail": "https://peako.shin0x.space/assets/thumb-uuid.jpg",
"composition": {
"fps": 30,
"durationSec": 15,
"size": { "width": 1080, "height": 1920 },
"background": { "type": "color", "value": "#000000" },
"tracks": [ ... ]
},
"blockSchema": {
"hero-video": {
"blockId": "hero-video",
"type": "video",
"label": "Hero Video",
"required": true,
"durationMode": "locked",
"position": { "startSec": 0, "durationSec": 15 },
"trackIndex": 0
},
"subtitle-main": {
"blockId": "subtitle-main",
"type": "subtitle",
"label": "Auto-Generated Subtitles",
"required": false,
"durationMode": "locked",
"position": { "startSec": 0, "durationSec": 15 },
"trackIndex": 1
}
},
"createdAt": 1709767500000
}
Always call GET /api/templates/:id and inspect blockSchema before rendering. It tells you exactly which blocks exist, what type they are, and whether they're required.
Error Codes:
401— Missing or invalid API key404— Template not found
List Templates
GET /api/templates
List all templates belonging to the authenticated user.
Headers:
X-API-Key: <your-api-key>(required)
Response:
[
{
"id": "template-uuid-1",
"name": "Social Media Short",
"description": "9:16 vertical video with subtitles",
"thumbnail": "https://peako.shin0x.space/assets/thumb.jpg",
"createdAt": 1709767500000
},
{
"id": "template-uuid-2",
"name": "Product Demo",
"description": null,
"thumbnail": null,
"createdAt": 1709767400000
}
]
Notes:
- Returns summaries only (no
compositionorblockSchema) - Sorted by
createdAtdescending (newest first)
Update Template
PUT /api/templates/:id
Update template name, description, thumbnail, or composition. All fields are optional.
Headers:
X-API-Key: <your-api-key>(required)Content-Type: application/json
Request Body (all fields optional):
{
"name": "Updated Name",
"description": "New description",
"thumbnail": "https://peako.shin0x.space/assets/new-thumb.jpg",
"composition": { ... }
}
Response: Same as Create Template response.
Error Codes:
400— Validation failed401— Missing or invalid API key404— Template not found
Delete Template
DELETE /api/templates/:id
Permanently delete a template.
Headers:
X-API-Key: <your-api-key>(required)
Response:
{
"id": "template-uuid",
"status": "deleted"
}
Error Codes:
401— Missing or invalid API key404— Template not found
Next: Rendering