# Portrait Subtitle Layout

> 竖屏视频字幕位置与参数配置 skill。适用于 9:16 或其他竖屏视频的字幕烧录、ASS 样式调整、安全区控制、替换或压住原视频自带字幕，以及“字幕别挡脸/别压底部按钮/盖住原字幕/字体太小/字幕超宽/字幕变成三行”这类字幕排版请求。当前版本只优化字幕参数，不处理遮罩、底板、背景条或毛玻璃效果。只要用户提到竖屏字幕位置、字号、边距、换行、盖住原字幕，都应优先使用这个 skill。

- Skill: `linyqh/portrait-subtitle-layout` (Agent Skill)
- Install (CLI): `npx skillmds@latest add linyqh/portrait-subtitle-layout`
- Raw SKILL.md: https://api.skillmd.com/api/skills/linyqh/portrait-subtitle-layout/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: linyqh (https://skillmd.com/u/linyqh)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/linyqh/portrait-subtitle-layout

---


# 竖屏视频字幕位置与参数

用于 **竖屏视频** 的字幕排版与烧录决策。当前版本的原则很明确：

- **先把字幕参数调对**
- **暂时不处理遮罩 / 底板 / 背景条**
- 靠 **字号、位置、行长、换行** 来优化效果

如果是横屏 / 16:9，请改用 `landscape-subtitle-layout`。

## 什么时候用

- 用户明确说是 **竖屏 / 9:16 / portrait** 视频
- 用户要字幕烧录，并且关心 **位置、安全区、字号、边距、换行**
- 用户说：**别挡人脸 / 再往上抬一点 / 底部还有按钮 / 字幕两行太满 / 字幕太小 / 字幕超宽**
- 用户说：**遮住原字幕 / 替换视频自带字幕 / 原字幕盖不住 / 三行太挤**

## 当前范围

这个 skill **只处理字幕参数**：

- `FontSize`
- `MarginV`
- `MarginL`
- `MarginR`
- `Outline`
- `Shadow`
- `WrapStyle`
- `MaxLineLength`
- 分句与拆事件策略

这个 skill **暂不处理**：

- 遮罩
- 底部黑条
- 半透明底板
- 毛玻璃背景
- 额外 `drawbox` / 背景滤镜

如果用户提到背景、底板、遮罩，当前回答应明确说明：**先移除遮罩，只保留字幕参数优化。**

## 先判断是哪一种模式

### A. 安全区上移模式 `safe-area`

适用于：

- 没有原片硬字幕需要遮挡
- 重点是 **别挡人脸 / 别压按钮 / 别压底部 UI**

### B. 原字幕压住模式 `cover-original-no-mask`

适用于：

- 原视频底部已经有自带硬字幕
- 新字幕需要尽量压住 / 替换原字幕
- 当前阶段 **不用任何遮罩**，只靠更大的字号和更低的位置处理

如果用户提到“遮住原字幕 / 替换原字幕 / 原字幕露出来了”，优先使用 `cover-original-no-mask`。

## 硬约束

1. **最多两行**；如果会变成三行，必须拆句或拆成多个字幕事件
2. **单行宽度目标不超过画面宽度的 `70%`**，极限不超过 `76%`
3. **先拆句，再缩字号**；不要一上来把字体缩小
4. `cover-original-no-mask` 下，字幕要 **足够低、足够大**，但不能裁切
5. 当前阶段 **禁止默认添加任何遮罩或背景条**

## 默认基准

以 **1080x1920** 竖屏为基准。

### 模式 A：安全区上移模式 `safe-area`

- `Alignment = 2`（bottom-center）
- `FontSize = 86`
- `MarginV = 600`
- `MarginL = 72`
- `MarginR = 72`
- `Outline = 4`
- `Shadow = 1`
- `WrapStyle = 2`
- `MaxLineLength = 12`

### 模式 B：原字幕压住模式 `cover-original-no-mask`

- `Alignment = 2`（bottom-center）
- `FontSize = 98`
- `MarginV = 118`
- `MarginL = 92`
- `MarginR = 92`
- `Outline = 3`
- `Shadow = 0`
- `WrapStyle = 2`
- `MaxLineLength = 8`

核心思路：

- 不靠黑条盖住旧字幕
- 靠更低的位置和更大的新字幕，尽量在视觉上替换旧字幕
- 如果仍然过长，就拆句或拆事件

## 缩放公式

如果分辨率不是 1080x1920，按下面规则缩放：

```text
safeFontSize    = clamp(round(86 * H / 1920), 60, 148)
safeMarginV     = clamp(round(600 * H / 1920), 360, 1200)
coverFontSize   = clamp(round(98 * H / 1920), 76, 164)
coverMarginV    = clamp(round(118 * H / 1920), 72, 220)
marginLSafe     = clamp(round(72 * W / 1080), 48, 132)
marginRSafe     = clamp(round(72 * W / 1080), 48, 132)
marginLCover    = clamp(round(92 * W / 1080), 56, 160)
marginRCover    = clamp(round(92 * W / 1080), 56, 160)
outlineSafe     = clamp(round(4 * H / 1920), 2, 6)
outlineCover    = clamp(round(3 * H / 1920), 2, 5)
```

其中：

- `W` = 视频宽度
- `H` = 视频高度

## 宽度与分句控制规则

如果用户反馈“字幕超出了视频宽度”或你预估会超宽，按下面顺序处理：

1. 把 `MaxLineLength` 收紧到 `6–8`
2. 主动拆句，优先在逗号、顿号、语义停顿点换行
3. 增加左右边距
4. 如果仍会超过两行，直接拆成两个字幕事件
5. 只有前面都做过了，才把字号下调 `4–6px`

## 字幕事件拆分规则

- 一条字幕如果会渲染成三行，必须拆成两个连续字幕事件
- 拆分优先点：`，`、`。`、`？`、`！`
- 拆分后每个事件目标为 `1–2` 行
- 不要为了保留原始整句而接受三行大字幕

## 位置调整规则

### 默认位置

- `safe-area`：`MarginV = 560–680`
- `cover-original-no-mask`：`MarginV = 96–140`

### 用户说“别挡到底部按钮 / 商品卡 / CTA”

只对 `safe-area` 生效：

- `MarginV = 680–820`
- 重度遮挡时可到 `820–960`

### 用户说“字幕太高了，想压低一点”

- `safe-area`：优先调到 `480–560`
- `cover-original-no-mask`：优先调到 `88–118`

### 用户说“别挡脸 / 别挡嘴部 / 别挡人物胸口”

优先处理顺序：

1. 先上移 `MarginV`
2. 再缩短每行长度
3. 再考虑略微缩字号

### 用户说“要盖住原视频自带字幕”

优先处理顺序：

1. 切到 `cover-original-no-mask`
2. 让字幕回到底部原字幕区域：`MarginV = 88–140`
3. 提大字号到 `98–106`
4. 把 `MaxLineLength` 收紧到 `6–8`
5. 如仍会三行，拆分成多个事件

## 失败判定

出现以下任一情况，说明参数方案失败，必须重做：

1. 新字幕变成三行或更多行
2. 新字幕超宽或被画面边缘裁切
3. `cover-original-no-mask` 下字幕仍然太小，视觉上压不住旧字幕
4. 回答里默认又加回了遮罩、底板、黑条或背景滤镜

## ASS 建议参数

### 安全区上移模式

```text
Style: Default,PingFang SC,86,&H00FFFFFF,&H000000FF,&H00000000,&H66000000,-1,0,0,0,100,100,0,0,1,4,1,2,72,72,600,1
```

### 原字幕压住模式（无遮罩）

```text
Style: Default,PingFang SC,98,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,3,0,2,92,92,118,1
```

重点：

- 不使用背景色来做底板
- 保留适度描边保证可读性
- 靠字号、位置、分句来尽量压住旧字幕

## FFmpeg 烧录示例

```bash
ffmpeg -y -i "IN.mp4" -vf "subtitles='SUB.ass'" \
  -c:v libx264 -preset medium -crf 19 \
  -c:a aac -b:a 128k -map 0:v:0 -map 0:a? -movflags +faststart "OUT.mp4"
```

说明：

- 当前版本不附加 `drawbox` 或其它背景滤镜
- 如果用户之前已经用了遮罩，当前应先移除遮罩，再单独调字幕参数

## 常见决策

### 口播 / talking head

- 使用 `safe-area`
- `MarginV = 700–900`
- `MaxLineLength = 10–12`

### 原片有自带底部字幕，但先不做遮罩

- 使用 `cover-original-no-mask`
- `FontSize = 98–106`
- `MarginV = 88–140`
- `MaxLineLength = 6–8`
- 超过两行就拆事件

### 用户直接说“字幕参数可以了，把遮罩去掉”

- 保留当前字幕参数方向
- 移除所有背景、底板、黑条、`drawbox`
- 只输出无遮罩版本的 `.ass` 样式或 FFmpeg 命令

## 输出要求

使用这个 skill 时，最终回答应包含：

1. 当前判定为竖屏的依据（分辨率或用户说明）
2. 当前选择的是 `safe-area` 还是 `cover-original-no-mask`，以及原因
3. 最终采用的字幕参数
4. 是否做了拆句/拆事件来避免三行
5. 明确说明：**当前版本已移除遮罩，只保留字幕参数优化**
6. 可直接使用的 `.ass` 样式或 FFmpeg 命令
7. 输出路径或建议输出文件名

