---
title: 타임라인 합성
description: Sume 호스트 스틸 하나와 비디오 하나를 같은 화면에 올립니다. Timeline 1.0용 MP4 샷 하나를 반환합니다.
---

> **현재 SoT.** Timeline 1.0 compose(`sume/timeline-1.0/compose`, #3976).
> dest와 prod. 이것은 **샷 하나**를 만듭니다. 조립 — 시퀀스, 트랜지션,
> 오디오 스파인 — 은 [Timeline 1.0](/models/timeline)에 남습니다.
> 이미지 다음 비디오를 이어 붙이는 것은 compose 모드가 **아닙니다**:
> 렌더의 인접 `video[]` 슬롯이 이미 그렇게 합니다.

Compose는 **스틸 하나** + **비디오 하나**를 받아 둘 다 한 화면에 있는
**MP4 하나**를 반환합니다. 서버가 워커 미디어 런타임에서 ffmpeg를
컴파일합니다(`apps/api/src/routes.ts` `createTimelineV1Compose` /
`submitSumeTimelineComposeJob`;
`packages/timeline-compiler/src/compose.ts`). 호출자는 필터그래프,
코덱, 셸 조각을 보내지 않습니다.

```text
POST /v1/timeline-1.0/compose
```

**`GET /v1/timeline-1.0/compose/:id`는 없습니다.** Job 봉투로 폴링하세요:

```text
GET /v1/jobs/:id/status
GET /v1/jobs/:id/result
```

호스티드 MCP: `timeline_compose`(`packages/mcp-server/src/mcp.ts`).
쓰기는 `idempotency_key`가 필요합니다(OAuth에서는 `mcp:write`). 흐름:
`timeline_compose` → `jobs_wait` → `jobs_result` → `video_url`을
`timeline_create` `video[]`에 넣습니다.

stack vs overlay의 HTTP 필드는 **`operation`**이지 `mode`가 아닙니다.
`mode`는 평소의 `async` / `sync` / `webhook` 통신 옵션입니다.

## 합성 만들기

필수: `operation`(`stack` \| `overlay`), `image.url`, `video.url`. 두
URL 모두 이 워크스페이스의 `media.sume.com` 아티팩트 또는 에셋이어야
합니다. `image.url`은 스틸이어야 하고(`compose_image_not_still`),
`video.url`은 비디오여야 합니다(`compose_video_not_video`). 먼저
가져오세요(`POST /v1/media-imports`). `Idempotency-Key`는 필수입니다.

선택: `layout`, `output`, `video.source_in`, `video.duration`, 평소의
`mode` / `webhook_url` / `wait_timeout_seconds` 통신 필드.

기본 `mode`는 **`async`**입니다. `mode: "sync"`를 주면 최대 **30초**
기다리고 끝난 Job을 `200`으로 주거나, `202`로 폴링합니다.

출력 길이는 **항상** 비디오 레이어에서 옵니다(`video.duration`, 없으면
`source_in`부터 파일 나머지). 스틸은 클립 전체 동안 홀드되며 길이를
늘릴 수 없습니다. 천장 **300**초
(`TIMELINE_COMPOSE_MAX_DURATION_SECONDS`). 소스를 넘으면 클램프됩니다
(`compose_duration_clamped_to_source`).

```bash
curl -X POST https://api.sume.com/v1/timeline-1.0/compose \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: timeline-compose-001" \
  -d '{
    "operation": "stack",
    "image": { "url": "https://media.sume.com/artifacts/artf_demo/banner.png" },
    "video": { "url": "https://media.sume.com/artifacts/artf_demo/talk.mp4" },
    "layout": { "split": "horizontal", "image_region": "top", "ratio": 0.5 },
    "output": { "width": 720, "height": 1280, "fps": 25 }
  }'
```

성공한 submit은 Job을 반환합니다(`model: sume/timeline-1.0/compose`).
`result_ready`이면 `GET /v1/jobs/:id/result`는
`kind: timeline_compose`이고 `video_url`(새 `artf_`)과
`duration_seconds`를 줍니다. 그 MP4를
[Timeline 1.0](/models/timeline) `video[]`에 넣으세요.

공개 요금: **Job당 $0.02 정액**(`TIMELINE_COMPOSE_PUBLIC_PRICING`;
`GET /v1/catalog`에서 확인). `video.duration`이 워커 프로브 전까지
생략될 수 있어서 정액입니다. 프로바이더 추론 없음 — 워커 ffmpeg만.

기본 출력은 **1080×1920** MP4이고 프레임레이트는 비디오 레이어 고유의
레이트입니다 — 프레임을 반복하거나 버리지 않는 유일한 레이트. 클립 레이트와
다른 `output.fps`를 명시하면 `output_fps_resamples_sources` 경고가
납니다. 조립할 타임라인에 맞춰
`output`을 두면 샷이 두 번 스케일되지 않습니다.

오디오는 비디오에서 통과합니다. 무음 비디오는 **경고**
(`compose_video_has_no_audio`)이지 실패가 아닙니다 — 클립은 렌더되고,
조립 때 Timeline 1.0 스파인이 오디오를 공급합니다.

## 레이아웃

`stack`은 한 프레임의 두 영역을 타일합니다. 기본값
`horizontal` / `top` / `0.5`가 반배너입니다(위 스틸, 아래 비디오).
`ratio`는 스틸 몫(0.1–0.9)이고 비디오가 나머지를 정확히 가져갑니다.

| `layout` 키 | `stack` | `overlay` |
|---|---|---|
| `split` | `horizontal` \| `vertical` | 불가 |
| `image_region` | 가로 분할은 `top` \| `bottom`; 세로 분할은 `left` \| `right` | 불가 |
| `ratio` | 스틸이 차지하는 프레임 비율 | 불가 |
| `image_fit` / `video_fit` | `cover` \| `contain` \| `stretch` (compose fit에 `blur` 없음) | `video_fit`만 |
| `position` | 불가 | `top` \| `center` \| `bottom` |
| `width_ratio` | 불가 | 너비의 0.05–1 (기본 0.9); 플레이트는 종횡비 유지 |
| `margin_ratio` | 불가 | 높이의 0–0.45 (기본 0.05) |

stack 키와 overlay 키를 섞으면 400
(`compose_stack_takes_no_overlay_layout` /
`compose_overlay_takes_no_stack_layout`).
축과 안 맞는 region은 `compose_image_region_wrong_axis`입니다.

## 거부 (안정 코드)

| 코드 | 언제 |
|---|---|
| `compose_image_not_still` | `image.url`이 스틸이 아님. |
| `compose_video_not_video` | `video.url`이 비디오가 아님. |
| `compose_image_region_wrong_axis` | 가로 분할에 `left`/`right`, 또는 세로 분할에 `top`/`bottom`. |
| `compose_stack_takes_no_overlay_layout` / `compose_overlay_takes_no_stack_layout` | 레이아웃 어휘를 섞음. |
| `compose_duration_clamped_to_source` | 경고: `video.duration`이 파일을 넘음. Job은 성공합니다. |
| `compose_video_has_no_audio` | 경고: 무음 비디오 소스. Job은 성공합니다. |
| `unsupported_media_source` / `source_not_found` | 호스트 밖 또는 죽은 URL. |
| 프로바이더 / ffmpeg 키 | 400 — `filtergraph`, `ffmpeg_args`, `codec`, `crf` 등. |

호스트 밖 URL(`https://example.com/…`)은 admit에서 거부됩니다. 먼저
가져오세요.

## 이 표면이 아닌 것

| 필요 | 사용 |
|---|---|
| 여러 클립 시퀀스 | [Timeline 1.0](/models/timeline) |
| 오디오 concat / split로 재사용 파일 | [타임라인 오디오](/models/timeline-audio) |
| 클립 하나의 `[start, end)` | [비디오 트림](/models/video-trim) |
| 픽셀 패스 (dim / crop) | [비디오 필터](/models/video-filter) |
| 오디오 트랙을 내구성 wav / mp3로 | [오디오 분리](/models/audio-detach) |

## 관련

- [Timeline 1.0](/models/timeline)
- [타임라인 오디오](/models/timeline-audio)
- [비디오 트림](/models/video-trim)
- [비디오 필터](/models/video-filter)
- [미디어 입력](/workflows/asset-library)
- [Job과 결과](/workflows/jobs-and-results)
- [MCP 도구와 게이트](/mcp/tools-and-gates)
