# Skill: full/headline — "כותרת וכתוביות שקטות" (Complete video)

The talking-head format of a CapCut creator with 300K followers, measured frame by frame on his Reels: a designed title over the first sentence (a heavy line, a serif line and a small tag on a deep-orange box), then ONE small line of subtitles under the face, a few big italic-serif beats with a punch-in, a brand logo above the subtitle when one is named, a soft beat 13 dB under the voice, and his outro — the call to action word by word after a warm flash and a white message card. Gemini 3.5 Flash picks the moments; one 720p render.

**Includes:** a designed title over the opening line · one quiet line of subtitles under the face · big italic beats with a punch-in · brand logos when named · his outro: the call to action word by word and a message card · soft music under the voice · pauses cut
**Built on:** kinetic `texts[]`, `panels`, `overlays` laid out by `POST /v1/studio/reel-style` (`"style": "headline"`) — no caption line; the nearest single looks are hook `rise` and captions `soft`
**Price:** 115–130 credits per finished minute · 30 s ≈ 64–74 credits
**Uses:** `/v1/speech/transcripts` · `/v1/studio/remove-silence` · `/v1/studio/reel-style` · `/v1/ai/text` · `/v1/ai/sound-effects` · `/v1/stock/icon` · `/v1/ai/music` · `/v1/studio/edit`

Base URL: `https://apihub.co.il` · Auth: `Authorization: Bearer <API key>` · Docs: `/docs`
Send the same `X-Tag: <job name>` header on every call of one video; `GET /v1/usage?tag=<job name>` then
returns exactly what it cost. Times in request bodies are **seconds on the edited (output) timeline**.
Unknown fields are rejected with the name of the right field — read the error instead of guessing.
**Files are kept 24 hours** (renders, uploads, generated clips/images/music) — download the finished video.

**Models — the cheapest that do the job.** AssemblyAI Universal-2 transcribes twice, Gemini 3.5
Flash (`quality: "balanced"`) watches the video once and picks the moments (Flash-Lite was tried and could not place the face),
ElevenLabs makes two short sounds (each reused) and a music bed exactly as long as the video, the icons are free; no AI video
or images. Everything is priced by the video's length.

---

## 1. Transcribe the video (once)

```jsonc
POST /v1/studio/uploads { "filename": "clip.mp4", "content_type": "video/mp4", "size_bytes": <bytes> }   // a local file → output.url (skip for a public link) · the original file, never a resized copy
POST /v1/speech/transcripts { "audio_url": "<video url>", "language_code": "he", "speech_models": ["universal-2"] }
// → T0, the video's words · Universal-2 · 64 s ≈ 1 credit
// optional — the music level: a WAV of the voice for the planner to measure (`cut_audio_url`); without it the bed sits at 0.25 (0.2 in the review)
POST /v1/studio/convert { "video_url": "<video url>", "output": { "format": "wav" } }                      // x-wait-ms: 90000 · ≈ 0.15 credits a second
```

**One transcript, on the video's own clock.** Every element the planner writes — the title, each subtitle, beat, pill,
chapter card, sticker, zoom and sound — is anchored to a word (`at` a word's id, or `during` a stretch of them).
The render finds the pauses in the sound itself (`remove_silence`, the same numbers every time), cuts them, and puts
each element on the exact output frame its word lands on; its answer reports where every one landed (`elements`:
exact / moved / lost). No second transcription of the cut audio, no reference transcript to put words back from. The
WAV is only where the planner measures the voice, to put the music ≈ 13 dB under it (16 dB in the review).

**Everything below is timed on the cut video's clock.**

His most common talking-head format (10 of the 23 videos): a designed title over the first sentence, then ONE small line of
subtitles under the face, a few big italic-serif beats with a punch-in, and a logo above the subtitle when a brand is named.

## 2. The first plan — the numbered words and the picker call

```jsonc
POST /v1/studio/reel-style
{ "style": "headline", "video_url": "<video url>", "transcript_id": "<T0>", "cut": { "from": "audio", "min_pause_ms": 200, "padding_ms": 70 },
  "cut_audio_url": "<the wav's url>" }                                                   // cut_audio_url optional (the music level)
// → output.words    [ { "i": 0, "text": "איזה", "start": 0.12, "end": 0.41 }, … ]   the numbered words (the output clock)
//   output.picker   { "system": "<the brief for this style>", "prompt": "The video is 57.24 s after the edit. Numbered words: …" }
//   output.summary / timeline / warnings   (every element of output.edit carries `at` / `during` on the words' ids)
```

It answers at once and costs a read request (1 credit).

## 3. Gemini watches the video and picks the moments

```jsonc
POST /v1/ai/text                           // Gemini 3.5 Flash ≈ 8–11 credits, ~35 s
{ "quality": "balanced", "json": true, "max_tokens": 8000, "temperature": 0.4,
  "system": "<output.picker.system>", "prompt": "<output.picker.prompt>",
  "media": [ { "url": "<video url>", "type": "video", "fps": 0.5 } ] }
```

It returns word numbers and short texts only: `corrections`, `face`, `title`, `emphasis`, `stickers` (icon names), `cta` and `music_brief`.
**Why Flash and not Flash-Lite:** on the example Flash-Lite (1 credit) copied the example face box instead of measuring it
(the layout is placed around the face), merged two list items into one and wrote a word the speaker never said in the title;
Gemini 3.5 Flash measured the face within ≈ 3 % (the chin at 53–56 % against 58 % measured), kept the title to his words
and fixed a misheard brand ("לגרוגבוט" → "לגרוק בוט"). Give it `max_tokens` 8000 — it thinks first, and 3000 cut one answer short.

**Your pass before using it:** every on-screen text must be the speaker's own words (drop a title word he never said);
keep only corrections that repair a real mistake; the `face` box must hold the face (top = the top of the head, bottom = the
chin, % of the 9:16 frame) — if a thumbnail (`POST /v1/studio/thumbnail`) shows otherwise, fix it; drop a sticker whose
icon is not in the lists below.

## 4. The assets — in parallel, each generated once

```jsonc
POST /v1/ai/sound-effects { "text": "soft airy whoosh swipe transition, clean, short, no reverb tail", "duration": 0.7, "prompt_influence": 0.5 }   // ≈ 1 credit
POST /v1/ai/sound-effects { "text": "short soft UI pop click for a label appearing, clean", "duration": 0.5, "prompt_influence": 0.5 }              // ≈ 1 credit
POST /v1/stock/icon { "icon": "<a sticker's icon>", "size": 512, "padding": 4 }   // one per sticker · free (Fluent Emoji MIT, SVG Logos CC0, Skill Icons MIT)
POST /v1/ai/music { "prompt": "<picks.music_brief>", "duration": <ceil(summary.output_seconds + 1)>, "instrumental": true }   // ≈ 0.77 credits a second
```

## 5. The final plan and ONE render

```jsonc
POST /v1/studio/reel-style
{ …the body of step 2…,
  …the picks as they came (without "music_brief"), each sticker with its "url" added…,
  "sounds": { "whoosh": "<mp3>", "pop": "<mp3>" },
  "music": { "url": "<music mp3>" } }                  // the volume comes from the measured voice
// → output.edit — the complete body of the render · output.timeline — what happens when (check it) · output.warnings
POST /v1/studio/edit <output.edit>          // x-wait-ms: 90000, then poll GET /v1/executions/{id} · 720p ≈ 0.77 credits a second
```

## What the plan puts in the render

Measured on the creator's Reels (1 fps sheets of every video, full frames around every change, colours sampled from the
pixels, ebur128 and spectrograms of the sound):

| The look (measured) | How the plan does it |
|---|---|
| Title block for the opening line (4.3–6 s): heavy sans line + condensed serif line + a small tag on a deep-orange box **#A83B01**, tilted −3°; no subtitles under it | `title` { text, sub, tag } → Heebo 900 / Frank Ruhl Libre 900 (Montserrat / Playfair Display for Latin and Cyrillic), each line fitted to ≈ 80 % of the width, effect `rise`, the tag `box`; in the band above the head when there is room, else under the face; until the end of the first sentence (2.2–5.5 s) with a slow 1.14→1.08 push |
| Subtitles: ONE line of 2–3 words, h 2.0 % (font ≈ 2.9 %), white + soft shadow, y ≈ 70 %, a new one every 0.9 s, fading in with a blur | phrases of ≤ 3 words / 1.5 s, Heebo 600 at 4 % (a little bigger for phones), a 9 % dark edge + shadow so they hold on a light shirt, `blur_in`, y = the chin + 12 % (60–80 %) |
| 2–4 beats in big condensed italic serif (h 6–7 %) with a punch-in | `emphasis` spans (1–3 words) → Frank Ruhl Libre 900 italic fitted to ≈ 74 % of the width (6.5–10.5 %), a 1.12× punch on the face, a pop |
| An app logo / icon above the subtitle when the thing is named (≈ 16 % of the width, 1–2 s) | `stickers` → 16 % wide above the subtitle (beside the face when that would cover it), 1.6 s, a gentle float and a pop |
| Every video of his ends the same way: a warm light-leak flash, the call to action ONE word at a time (heavy white, h 2.9 %, ≈ 0.7 s a word) and a white "message" card | `cta` (the first word of the call to action, only when he says one) → a #FFF3D6 flash (0.34 s), Heebo 900 / Montserrat 900 at 5 %, word by word, and the whole line in dark type on a white card for the last ≈ 2.6 s, a 1.1× punch, a whoosh |
| A soft beat under the voice that never stops: in the gaps the mix drops only 12–19 dB (a bed ≈ 13 dB under the voice), few effects | `music.volume` = 10^((voice LUFS + 5) / 20) from the WAV (−12 LUFS → 0.45, −18 → 0.22; 0.25 when it cannot measure), `duck: false`; a whoosh into the title / board / point / outro, pops on stickers and beats (≤ 26 hits from 2 files); `audio.normalize` → −16 LUFS |
| No pauses | `remove_silence` 200/70 from the audio |
| A warm, slightly contrasty grade | `color` contrast 1.05, saturation 1.05, temperature +0.12, vignette 0.2; 9:16, 720×1280 |

## Tune it

`title` (your own words — only what is said) · `emphasis` · `face` · `seed` · `resolution: "1080"` · `speed` 1–1.25 · `cut: false` to keep every pause · `cut.from: "words"` for a transcript whose words
have real gaps. Every field of the returned `edit` can still be changed before the render.

## What the engine cannot do yet (so the plan does not try)

Rounded label and pill corners (text boxes are square); a box behind ONE word of a line (his purple key word — the plan
boxes the whole phrase instead); glow on text; emoji inside text (✅ ❌ are stickers beside it); the speaker cut out of the
background or in a circle on a card; a screen recording in a phone mockup on a coloured card (overlays are drawn below
panels — his tutorial parts); hand-drawn marks (the red ring around a link, arrows); a real light leak (a warm flash instead).

## What the example cost and how long it took

The example on /skills: the owner talking in his car — 62 s, Hebrew, one take, 1080×1920 HEVC, −12.2 LUFS — → 57.2 s,
720×1280. The title "איזה מגניב היה / אם היה אפשר לייצר סוכן" with the tag "30 רילסים" over the first 5.5 s, 50 subtitles, 4 beats ("יש כלי כזה!", "אפליקציה", "30 רילסים", "למודלים AI"), a biceps emoji and the Instagram logo, and his outro on "תשאירו לי פרטים ותקבלו לינק"; −15.8 LUFS, the bed at 0.45 from the measured −12 LUFS voice. The planner put back "ובעצם האפליקציה תייצר לכם", which the cut audio's transcript had lost; the picker fixed "לגרוגבוט" → "לגרוק בוט" and measured the face at 25–60 % (58 % measured). Made with these steps on the dev server (tag `insta-headline-car`, `GET /v1/usage?tag=…`):

| Step | Credits | Time |
|---|---|---|
| Upload (124 MB) | 1 | 1.1 min |
| Transcribe the original (Universal-2, 63 s) | 1 | 12–16 s |
| Pauses cut, sound only (WAV, 58 s) | 9 | 4–7 s |
| Transcribe the cut (Universal-2, 58 s) | 1 | 6–9 s |
| Plan ×2 (POST /v1/studio/reel-style) | 2 | 2–3 s |
| Gemini 3.5 Flash picks | 15 | 49 s |
| 2 sound effects + 3 icons | 2 | 5 s (parallel) |
| Music, 59 s | 45 | 14 s |
| Render (720p, 57.2 s) | 44 | 3.3 min |
| **Total** | **120** | **≈ 6 min** |

The music and the render are ≈ 75 % of it; without music a minute is ≈ 80 credits. A finished minute ≈ 118–126 credits,
a 30-second video ≈ 64–74. Until the render engine's join fix is deployed to the Lambda, each cut adds a few
milliseconds of silence to the voice, so near the end of a 55-second edit the words appear up to ≈ 0.15 s before they are said.

Stickers: brand logos `skill-icons:instagram`, `logos:facebook`, `logos:tiktok-icon`, `logos:youtube-icon`, `logos:whatsapp-icon`, `logos:telegram`, `logos:google-gemini`, `logos:openai-icon`, `logos:grok`, `logos:x`, `skill-icons:linkedin`, `logos:apple`, `logos:android-icon` and 54 Fluent emoji (`fluent-emoji-flat:<name>`).

Send `x-wait-ms: 110000` to wait for the render in the same call; if the response is still
`processing`, poll `GET /v1/executions/{id}` until `status` is `completed` and read `output.url`.

## Check the bill

`GET /v1/usage?tag=<job name>` — per call, per operation and the total, in credits. Quote that to the
customer, not the estimate above.

## Rules that keep captions readable on every platform

- **Safe zone.** Keep text inside the middle 80% of the frame: `side_margin` ≥ 6 handles the sides; `margin`
  ≥ 12 keeps the bottom clear of the platform UI (username, buttons, progress bar).
- **A line never leaves the frame** — a line too wide for the side margins is set smaller automatically. Do
  not shrink the size yourself, wrap instead (`max_chars_per_line`).
- **Hebrew has no capitals** — keep `uppercase: false`; it only breaks Latin words mixed into a sentence.
- **Fonts.** `GET /v1/studio/fonts` lists the bundled families and which scripts they draw. A font that
  cannot draw the caption's language is swapped and reported in `warnings`.
- The customer's transcript wins: to fix a word, `GET /v1/speech/transcripts/{id}/captions`, edit the text,
  and send the list back as `captions.captions` — timing is kept when the word count is unchanged.
