PHP script to generate TikTok-style subtitles with word-level highlighting from Whisper JSON files.
- Smart Grouping: Groups words into 2-3 word phrases
- Perfect Sync: Uses exact word-level timing from Whisper JSON
- Adaptive Layout: Auto-detects video dimensions and adjusts font/margins
- Word Highlighting: Red background highlights each word as spoken with smooth fade
- Time Control: Adjustable timing offset and speed multiplier
- Fully Configurable: Every parameter configurable from command line
- Tight Box Fit: Boxes fit perfectly around words with configurable padding
- Text Shadow & Borders: Optional shadow and border effects
- PHP 7.0+
- FFmpeg and FFprobe in PATH
# Basic usage
php tiktok_pro.php --video=input.MOV --json=words.json
# With fade effect and shadow
php tiktok_pro.php --video=input.MOV --json=words.json --style=fade --fade-ms=120 --text-shadow=2
# Fix timing offset
php tiktok_pro.php --video=input.MOV --json=words.json --offset=1.0Whisper-style JSON with word-level timestamps:
{
"words": [
{"word": "Hello", "start": 0.0, "end": 0.5},
{"word": "world", "start": 0.5, "end": 1.0}
]
}| Parameter | Description |
|---|---|
--video |
Input video file path |
--json |
Whisper JSON file with word timings |
| Parameter | Description | Default |
|---|---|---|
--bg-color |
Background color hex (no #) | FF0000 |
--text-color |
Text color hex (no #) | FFFFFF |
--outline-color |
Text outline color hex (no #) | 000000 |
--text-outline |
Outline width in pixels | 3 |
--text-shadow |
Shadow depth (0 = none) | 0 |
--style |
Animation: solid, fade, pulse | solid |
--fade-ms |
Fade duration in milliseconds | 100 |
| Parameter | Description | Default |
|---|---|---|
--position |
Position: top, center, bottom | center |
--font-size |
Font size in pixels | auto |
--font-name |
Font family | Arial |
--margin-h |
Horizontal margin in pixels | auto |
--margin-v |
Vertical margin in pixels | auto |
--padding-x |
Box horizontal padding | auto |
--padding-y |
Box vertical padding | auto |
--border-radius |
Box corner radius | 15 |
--box-border |
Box border width (0 = none) | 0 |
--box-border-color |
Box border color hex (no #) | 000000 |
--extra-width |
Extra box width padding | 0 |
| Parameter | Description | Default |
|---|---|---|
--max-words |
Max words per group | 4 |
--max-chars |
Max characters per line | 40 |
--gap-threshold |
Gap to split groups (seconds) | auto |
| Parameter | Description | Default |
|---|---|---|
--output |
Output video file path | auto |
--offset |
Shift all subtitles by seconds (+delay, -advance) | 0 |
--min-duration |
Min duration for zero-duration words | 0.08 |
--no-burn |
Generate ASS only, skip video | false |
| Parameter | Description | Default |
|---|---|---|
--video-codec |
Video codec | libx264 |
--video-preset |
Preset: ultrafast/fast/medium/slow | medium |
--video-crf |
Quality: 0-51 (lower = better) | 23 |
--pixel-format |
Pixel format | yuv420p |
php tiktok_pro.php --video=input.MOV --json=words.json \
--style=fade --fade-ms=120 --text-shadow=2 \
--offset=1.0 --extra-width=0# Subtitles appear early: add delay
php tiktok_pro.php --video=input.MOV --json=words.json --offset=1.0
# Subtitles appear late: reduce delay
php tiktok_pro.php --video=input.MOV --json=words.json --offset=-0.3# Green background
php tiktok_pro.php --video=input.MOV --json=words.json --bg-color=00FF00
# Yellow background with black text
php tiktok_pro.php --video=input.MOV --json=words.json \
--bg-color=FFFF00 --text-color=000000 --outline-color=FFFFFFphp tiktok_pro.php --video=input.MOV --json=words.json \
--box-border=2 --box-border-color=FFFFFF --border-radius=20# Tight fit (no extra space)
php tiktok_pro.php --video=input.MOV --json=words.json --extra-width=0
# Loose fit (more padding)
php tiktok_pro.php --video=input.MOV --json=words.json --extra-width=20# Shorter groups (2 words max)
php tiktok_pro.php --video=input.MOV --json=words.json --max-words=2
# Custom gap threshold
php tiktok_pro.php --video=input.MOV --json=words.json --gap-threshold=0.5php tiktok_pro.php --video=input.MOV --json=words.json \
--position=bottom --margin-v=50php tiktok_pro.php --video=input.MOV --json=words.json \
--video-crf=18 --video-preset=slowphp tiktok_pro.php --video=input.MOV --json=words.json --no-burn- Detects video properties (resolution, FPS, duration) via FFprobe
- Parses Whisper JSON and applies time offset and speed multiplier
- Fixes zero-duration words (adds minimum 80ms visibility)
- Groups words intelligently based on timing gaps and pauses
- Generates ASS subtitle file with two layers:
- Layer 1: White text visible for entire group duration
- Layer 0: Red background highlight for each word with fade-out transition
- Burns subtitles into video using FFmpeg with configurable encoding
Add positive offset: --offset=1.0
Add negative offset: --offset=-0.3
Use tight fit: --extra-width=0
Increase fade duration: --fade-ms=150 with --style=fade
MIT License