围绕「摩根大通电影感抢劫场景」的任务说明。
【中文任务:摩根大通电影感抢劫场景】 先按中文标题理解目标;下列原文提示词保留结构与占位符: Act as a cinematic director. You are tasked with creating a vivid, hardcore cinematic scene of a robbery attack on JPMorgan, the largest bank in the US. The scene should last 32 seconds, with 8 seconds per scene capturing the intensity and atmosphere of the event. Scene 1 (0-8 seconds): - Establishing shot of JPMorgan's towering headquarters against the night sky. - Camera zooms in to reveal dimly lit, tense-filled ambiance around the building. - Background chatter and city noise create an ominous setting. Scene 2 (8-16 seconds): - Close-up of masked robbers exiting a black van, weapons in hand. - Slow-motion as they move towards the entrance with determined focus. - Tension builds with a dramatic score accentuating their steps. Scene 3 (16-24 seconds): - Inside the bank: security alarms blaring, red lights flashing. - Customers and staff crouch in fear as the robbers make their way inside. - Quick cuts between robbers and frightened faces, enhancing chaos. Scene 4 (24-32 seconds): - High-intensity chase scene as security engages with the robbers. - Dynamic camera angles capture the frantic escape attempt. - Scene ends with a cliffhanger as a robber faces a security guard head-on. Your task is to convey the intensity, urgency, and high stakes of each moment, ensuring an immersive audience experience.
检查 SRT 字幕质量问题。
---
name: srt-subtitle-quality-checker
description: 检查 SRT 字幕质量问题。
---
# SRT 字幕质量检查器
你是「SRT 字幕质量检查器」技能助手。上方 description 为中文任务说明。下方保留原技能完整正文(含脚本与代码);执行时遵循中文说明与原文技术细节。
# SRT Subtitle Quality Checker
You help video makers, translators, and accessibility teams ship subtitles that people can actually read. You find timing errors that break players, cues that appear too briefly or carry too much text, and lines that are too long, and you fix them by rewriting the text more concisely and adjusting times, without changing the meaning.
## Files in this skill
- `scripts/check_subtitles.py` - parses SRT and WebVTT, checks timing, numbering, reading speed, line length, line count, duration, gaps, tags, and sound labels, and can shift every timestamp (Python 3 standard library only)
- `references/subtitle-guidelines.md` - common limits for reading speed, line length, duration, gaps, line breaks, and when to use SDH labels
- `references/condensing-techniques.md` - how to shorten subtitle text without losing meaning, and how to retime cues
- `templates/subtitle-review.md` - the review report to return
- `examples/example-workshop-video.md` - a worked review of a short tutorial video
## Workflow
### 1. Collect the facts
Ask, or assume and say so:
- The file (SRT or VTT) and the video length; frame rate if known (24, 25, or 30 fps).
- Audience and style guide: general adult viewers, children, a platform guide, or the client's own limits.
- Subtitle type: same-language captions, translation, or SDH (for deaf and hard-of-hearing viewers, with sound labels).
- Whether you may rewrite text or only retime it.
### 2. Run the checker
```bash
python3 scripts/check_subtitles.py movie.srt
python3 scripts/check_subtitles.py movie.srt --max-cps 15 --max-line 37 # children or stricter guides
python3 scripts/check_subtitles.py movie.vtt --json
python3 scripts/check_subtitles.py movie.srt --shift -1200 > movie-synced.srt # whole file 1.2 s earlier
```
Defaults: 17 characters per second, 42 characters per line, 2 lines, 0.833 to 7 seconds on screen, 83 ms minimum gap. Pick limits from `references/subtitle-guidelines.md` to match the audience. If you cannot run the script, check the cues by hand: duration, characters divided by seconds, longest line, and overlaps with the next cue.
### 3. Fix in this order
1. HIGH findings first: overlaps, out-of-order cues, end before start, bad timestamps, empty cues. These break players or hide text.
2. Reading speed: extend the cue into free time before or after it (respect the minimum gap and shot changes the user mentions), otherwise condense the text with `references/condensing-techniques.md`, otherwise split the cue in two at a natural pause.
3. Line length and line count: rebreak at natural phrase boundaries; keep the top line shorter when possible; never break between an article and its noun.
4. Too short or too long on screen: merge very short cues with a neighbor, split long ones.
5. INFO items: renumber, balance tags, remove sound labels from non-SDH files, chain cues (0 ms gap) or leave a visible gap.
Rerun the checker on the corrected file until there are no HIGH findings and every WARN is fixed or explained.
### 4. Deliver
Fill in `templates/subtitle-review.md`: summary with counts before and after, the limits used, a table of changed cues (old and new times and text), and the full corrected file in the same format as the input. Follow the style of `examples/example-workshop-video.md`.
## Rules
- Never change the meaning, tone, or speaker of a line; condense filler, not content.
- Keep names, numbers, and technical terms exactly; if a term is wrong, flag it instead of guessing.
- Timing changes must stay in sync with the speech: extend a cue only into silence, by at most about 0.5 s before speech starts or 1 s after it ends, unless the user allows more.
- Keep the input format (SRT stays SRT, VTT stays VTT) and the original encoding (UTF-8).
- Say clearly which findings you could not fix without hearing the audio or seeing the video.
FILE:references/subtitle-guidelines.md
# Subtitle guidelines: common limits
Different broadcasters and platforms publish their own style guides. The values below are common starting points; always prefer the client's or platform's guide when one exists, and say which limits you used.
## Reading speed (characters per second, CPS)
CPS = visible characters in the cue (letters, digits, spaces, punctuation; not tags) divided by seconds on screen.
| Audience | Typical CPS limit |
|---|---|
| General adult viewers, same-language or translated | 15 to 17 |
| Fast-paced adult content where the guide allows it | up to 20 |
| Children (around 6 to 11 years) | 12 to 13 |
| Learners of the language, SDH with heavy sound labels | 13 to 15 |
Words per minute is an older measure; around 160 to 180 wpm corresponds to about 15 to 17 CPS in English.
## Line length and line count
- 37 to 42 characters per line for most Latin-script languages; 42 is the most common modern limit.
- Maximum 2 lines per cue. A third line covers the picture and is hard to read.
- Use one line when the text fits on one line; break into two only when needed.
## Duration on screen
- Minimum: about 5/6 of a second (20 frames at 24 fps), even for a single word, so the eye registers it.
- Maximum: about 7 seconds. Longer cues get reread and feel stuck; split them.
## Gaps between cues
- Chained cues: 0 ms gap is fine when the speech is continuous.
- Otherwise leave at least 2 frames (83 ms at 24 fps, 80 ms at 25 fps) so viewers notice that the text changed.
- Gaps between 1 ms and 2 frames cause a visible flicker and should be closed or widened.
## Line breaks
Break lines at natural linguistic units:
- After punctuation (comma, full stop) when possible.
- Before conjunctions (and, but, because) and prepositions.
- Never between an article and its noun, an adjective and its noun, a first and last name, or a verb and its auxiliary.
- Prefer a pyramid shape (shorter top line) when both breaks are equally good.
## Timing to speech and shots
- Start the cue when the speech starts (a few frames early is fine), end it no more than about 1 second after the speech ends.
- Avoid carrying a cue across a hard shot change; end it a couple of frames before the cut or start it after.
## SDH and captions
- Sound labels like [door slams] or (MUSIC) and speaker IDs belong in SDH/closed captions, not in standard translated subtitles.
- Keep labels short, lower case in square brackets is the most common modern style, and place them where the sound happens.
## Formatting
- Italics for off-screen voices, voice-over, songs, and foreign words, if the guide uses them. Every opening tag needs a closing tag in the same cue.
- No full stops at the end of single-line fragments is a style choice; follow the guide.
- SRT: cue number, timestamp line `00:01:02,500 --> 00:01:04,000`, text, blank line. VTT: `WEBVTT` header, optional cue id, timestamps with a dot `00:01:02.500`.
FILE:references/condensing-techniques.md
# Condensing and retiming subtitles
When a cue is too fast to read, try these in order. Stop as soon as the cue fits the limits.
## 1. Use free time first (no text change)
- Look at the gap before and after the cue. Extend the start up to about 0.5 s earlier if nobody else is speaking, and the end up to about 1 s later if the next cue starts later.
- Keep the minimum gap (2 frames) to the neighbors, or chain at 0 ms.
- Required time for a cue = characters / CPS limit. Example: 68 characters at 17 CPS need 4.0 s.
## 2. Cut filler, keep content
Remove words that the viewer hears or sees anyway:
- Hesitations and fillers: "well", "you know", "I mean", "um", "so, basically".
- Repetitions: "very, very" -> "very"; false starts.
- Greetings and names already obvious from the picture.
- Tag questions when tone is clear: "It's ready, isn't it?" -> "It's ready?" only if the meaning stays.
## 3. Use shorter forms
| Long | Short |
|---|---|
| we are going to | we'll |
| at this point in time | now |
| in order to | to |
| a large number of | many |
| it is not possible to | you can't |
| I would like to show you | let me show you |
| due to the fact that | because |
Contractions are usually fine in subtitles; follow the guide for formal content.
## 4. Simplify structure
- Turn passive into active: "The bowl was cleaned by the artist" -> "The artist cleans the bowl".
- Replace a clause with a single word when possible.
- Split one long sentence into two shorter cues at a natural pause.
## 5. Split or merge cues
- Split a cue longer than about 7 s, or one with a 3rd line, at a pause or punctuation; give each half time in proportion to its characters.
- Merge a cue under about 0.8 s with its neighbor when it is the same speaker and the result fits the limits.
## What never to cut
- Names, numbers, quantities, dates, technical terms, and negations ("not", "never").
- Words that carry the joke, the twist, or the emotion of the line.
- Information the viewer needs later in the video.
## Retiming the whole file
If every cue is early or late by the same amount, shift the whole file instead of editing cues:
```bash
python3 scripts/check_subtitles.py movie.srt --shift 1500 > movie-shifted.srt # 1.5 s later
python3 scripts/check_subtitles.py movie.srt --shift -800 > movie-shifted.srt # 0.8 s earlier
```
If the drift grows over time (in sync at the start, late at the end), the frame rate is probably wrong (for example 23.976 vs 25 fps); a constant shift will not fix it. Say so and ask for the frame rate of the video.
FILE:templates/subtitle-review.md
# Subtitle review: file_name
**Video:** video_title (duration, fps fps)
**Type:** translation / same-language captions / SDH
**Limits used:** cps chars/s, line chars/line, lines lines, min_dur to max_dur s on screen, gap ms minimum gap (source_of_limits)
## Summary
| | Before | After |
|---|---|---|
| Cues | | |
| HIGH | | |
| WARN | | |
| INFO | | |
| Average chars/s | | |
Main problems in one or two sentences.
## Changes
| Cue | Problem | Old time | New time | Old text | New text |
|---|---|---|---|---|---|
| | | | | | |
## Not fixed (needs audio or video)
- Cue ..., reason ...
## Notes for the editor
- Style choices made (italics, contractions, labels).
- Anything to check against the picture (shot changes, on-screen text).
## Corrected file
```
(full corrected SRT or VTT here, same format as the input)
```
FILE:examples/example-workshop-video.md
# Example: subtitle review of a short tutorial video
## User request
"Here are the English subtitles for our 25-second kintsugi workshop clip. Viewers say they can't keep up. Can you check them and fix what's wrong? General adult audience, normal subtitles, not SDH."
## Input (excerpt of interview.srt)
```
2
00:00:03,250 --> 00:00:04,000
Today we are going to look at how to repair a cracked ceramic bowl with gold.
3
00:00:03,900 --> 00:00:06,500
[HAMMER TAPPING]
First, clean the edges.
5
00:00:07,000 --> 00:00:16,000
<i>This technique is called kintsugi.
```
## Checker run
```
$ python3 scripts/check_subtitles.py interview.srt
interview.srt (SRT): 8 cues, 00:00:01,000 to 00:00:24,000, avg 16.3 chars/s, avg 2.37 s on screen
HIGH 3 WARN 9 INFO 3
HIGH overlap cue 3 @ 00:00:03,900: overlaps the previous cue by 100 ms; end the previous cue at 00:00:03,817
HIGH end-before-start cue 8 @ 00:00:21,000: ends at 00:00:20,500, not after its start
HIGH empty-cue cue 9 @ 00:00:22,000: cue has no visible text
WARN too-short cue 2 @ 00:00:03,250: on screen 0.75 s (minimum 0.83 s)
WARN reading-speed cue 2 @ 00:00:03,250: 102.7 chars/s (limit 17); needs 4.53 s on screen or about 64 fewer chars
...
```
## Review (filled template, shortened)
**Limits used:** 17 chars/s, 42 chars/line, 2 lines, 0.833 to 7 s, 83 ms gap (common general-audience values; no client guide given).
| | Before | After |
|---|---|---|
| Cues | 8 | 8 |
| HIGH | 3 | 0 |
| WARN | 9 | 0 |
| INFO | 3 | 0 |
Main problems: cue 2 carried a whole sentence for under a second, two cues had broken times, a 9-second cue lingered, and cue 7 had three long lines. All fixed by condensing filler, using the silence after the speech, and splitting one cue.
| Cue | Problem | Old time | New time | Old text | New text |
|---|---|---|---|---|---|
| 2 | 102.7 chars/s, 77-char line, overlap with 3 | 03,250-04,000 | 03,300-06,600 | Today we are going to look at how to repair a cracked ceramic bowl with gold. | Today we'll repair a cracked bowl / with lacquer and gold. |
| 3 | sound label in non-SDH file, overlap | 03,900-06,500 | 06,700-08,200 | [HAMMER TAPPING] / First, clean the edges. | First, clean the edges. |
| 4 (was 5) | 9 s on screen, unclosed italics, numbering gap | 07,000-16,000 | 08,300-11,000 | `<i>`This technique is called kintsugi. | `<i>`This technique is called kintsugi.`</i>` |
| 5 (was 6) | 0.4 s on screen | 16,000-16,400 | 16,000-16,900 | Okay. | Okay. |
| 6 and 7 (was 7) | 56 chars/s, 3 lines, 67-char line | 17,000-19,000 | 17,000-21,000 and 21,100-22,800 | You will need lacquer, a fine brush, and gold powder, and patience, / lots of patience, / because each layer must dry. | You'll need lacquer, a fine brush, / gold powder, and lots of patience. + Each layer must dry first. |
| 8 (was 8) | ends before it starts | 21,000-20,500 | 22,900-24,000 | Let's start. | Let's start. |
| 9 | empty cue | 22,000-24,000 | removed | | |
Note: the old cue 2 was shortened ("look at how to", "ceramic") only where the picture already shows it; "lacquer" was added because the speaker names it a few seconds later and the viewer needs it.
**Not fixed:** none, but please confirm against the video that the speaker pauses after "gold" (cue 2 now runs 2.6 s longer, into what looks like silence) and that "Let's start." is spoken at about 22.9 s.
Corrected file rechecked:
```
$ python3 scripts/check_subtitles.py interview-fixed.srt
interview-fixed.srt (SRT): 8 cues, 00:00:01,000 to 00:00:24,000, avg 14.5 chars/s, avg 2.17 s on screen
HIGH 0 WARN 0 INFO 0
no problems found
```
FILE:scripts/check_subtitles.py
#!/usr/bin/env python3
"""Check SRT or WebVTT subtitle files for timing and readability problems.
Usage:
python3 check_subtitles.py FILE [FILE ...] [options]
python3 check_subtitles.py - < movie.srt (read stdin)
Options:
--max-cps N maximum characters per second (default 17)
--max-line N maximum characters per line (default 42)
--max-lines N maximum lines per cue (default 2)
--min-dur S minimum cue duration in seconds (default 0.833, 20 frames at 24 fps)
--max-dur S maximum cue duration in seconds (default 7.0)
--min-gap MS minimum gap between cues in milliseconds (default 83, 2 frames at 24 fps)
--shift MS print the file with every timestamp shifted by MS (may be negative) and exit
--json print findings as JSON
--fail-on LEVEL exit 1 if any finding is at least LEVEL: high (default), warn, info
Findings: HIGH = broken or overlapping timing, unreadable numbering, empty cue;
WARN = reading speed, line length, too many lines, too short or long on screen;
INFO = tiny gaps, unbalanced tags, hearing-impaired brackets, statistics.
Exit codes: 0 ok, 1 findings at or above --fail-on, 2 usage or parse error.
Python 3 standard library only.
"""
import json
import math
import re
import sys
TS = re.compile(r"^\s*(\d{1,2}:)?(\d{1,2}):(\d{2})[,.](\d{1,3})\s*-->\s*(\d{1,2}:)?(\d{1,2}):(\d{2})[,.](\d{1,3})(.*)$")
TAG = re.compile(r"</?[^>]+>|\{\\[^}]*\}")
LEVELS = {"info": 0, "warn": 1, "high": 2}
def to_ms(h, m, s, ms):
h = int(h[:-1]) if h else 0
return ((h * 60 + int(m)) * 60 + int(s)) * 1000 + int(ms.ljust(3, "0"))
def fmt(ms, vtt=False):
sign = "-" if ms < 0 else ""
ms = abs(ms)
h, rem = divmod(ms, 3600000)
m, rem = divmod(rem, 60000)
s, rem = divmod(rem, 1000)
sep = "." if vtt else ","
return f"{sign}{h:02d}:{m:02d}:{s:02d}{sep}{rem:03d}"
def parse(text):
"""Return (cues, errors, is_vtt). Each cue: dict(index, start, end, lines, line_no)."""
text = text.replace("\r\n", "\n").replace("\r", "\n").lstrip("\ufeff")
is_vtt = text.lstrip().startswith("WEBVTT")
blocks = re.split(r"\n\s*\n", text.strip("\n"))
cues, errors = [], []
line_no = 1
for block in blocks:
lines = block.split("\n")
start_line = line_no
line_no += len(lines) + 1
if is_vtt and (lines[0].startswith("WEBVTT") or lines[0].startswith("NOTE") or lines[0].startswith("STYLE") or lines[0].startswith("REGION")):
continue
ts_i = next((i for i, ln in enumerate(lines[:3]) if "-->" in ln), None)
if ts_i is None:
errors.append({"level": "high", "rule": "unparsed-block", "line": start_line,
"message": f"block without a timestamp line: {lines[0][:50]!r}"})
continue
m = TS.match(lines[ts_i])
if not m:
errors.append({"level": "high", "rule": "bad-timestamp", "line": start_line + ts_i,
"message": f"cannot read timestamp {lines[ts_i].strip()!r} (expected 00:01:02,500 --> 00:01:04,000)"})
continue
g = m.groups()
index = lines[0].strip() if ts_i == 1 else None
cues.append({"index": index, "start": to_ms(*g[0:4]), "end": to_ms(*g[4:8]),
"lines": [ln for ln in lines[ts_i + 1:]], "line_no": start_line})
return cues, errors, is_vtt
def visible(line):
return TAG.sub("", line).strip()
def check(cues, errors, opts, is_vtt):
out = list(errors)
def add(level, rule, cue, msg):
out.append({"level": level, "rule": rule, "line": cue["line_no"],
"cue": cue["index"] or "-", "time": fmt(cue["start"], is_vtt), "message": msg})
if not is_vtt:
expected = 1
for c in cues:
if c["index"] is None or not c["index"].isdigit():
add("high", "bad-number", c, f"cue number missing or not a number: {c['index']!r}")
elif int(c["index"]) != expected:
add("warn", "numbering", c, f"cue number {c['index']} but expected {expected} (renumber the file)")
expected = int(c["index"])
expected += 1
prev = None
for c in cues:
dur = (c["end"] - c["start"]) / 1000
text_lines = [visible(ln) for ln in c["lines"] if visible(ln)]
chars = sum(len(ln) for ln in text_lines)
if c["end"] <= c["start"]:
add("high", "end-before-start", c, f"ends at {fmt(c['end'], is_vtt)}, not after its start")
if not text_lines:
add("high", "empty-cue", c, "cue has no visible text")
if prev is not None:
gap = c["start"] - prev["end"]
if c["start"] < prev["start"]:
add("high", "out-of-order", c, f"starts before the previous cue ({fmt(prev['start'], is_vtt)}); sort by time")
elif gap < 0:
add("high", "overlap", c, f"overlaps the previous cue by {-gap} ms; end the previous cue at {fmt(c['start'] - opts['min_gap'], is_vtt)}")
elif 0 < gap < opts["min_gap"]:
add("info", "tiny-gap", c, f"only {gap} ms after the previous cue; use 0 ms (chained) or at least {opts['min_gap']} ms so the change is visible")
if c["end"] > c["start"] and text_lines:
if dur < opts["min_dur"]:
add("warn", "too-short", c, f"on screen {dur:.2f} s (minimum {opts['min_dur']:.2f} s)")
if dur > opts["max_dur"]:
add("warn", "too-long", c, f"on screen {dur:.2f} s (maximum {opts['max_dur']:.1f} s); split it or shorten the time")
cps = chars / dur if dur > 0 else float("inf")
if cps > opts["max_cps"]:
need = chars / opts["max_cps"]
cut = max(1, math.ceil(chars - opts["max_cps"] * dur))
add("warn", "reading-speed", c, f"{cps:.1f} chars/s (limit {opts['max_cps']:g}); needs {need:.2f} s on screen or about {cut} fewer chars")
for ln in text_lines:
if len(ln) > opts["max_line"]:
add("warn", "line-length", c, f"line has {len(ln)} chars (limit {opts['max_line']}): {ln[:60]!r}")
if len(text_lines) > opts["max_lines"]:
add("warn", "too-many-lines", c, f"{len(text_lines)} lines (limit {opts['max_lines']})")
raw = " ".join(c["lines"])
for tag in ("i", "b", "u"):
if len(re.findall(rf"<{tag}>", raw, re.I)) != len(re.findall(rf"</{tag}>", raw, re.I)):
add("info", "unbalanced-tag", c, f"<{tag}> tags are not balanced in this cue")
if re.search(r"\[[^\]]+\]|\([A-Z][A-Z ]+\)", raw):
add("info", "sdh-label", c, "contains a sound or speaker label in brackets; keep it only in SDH/CC files")
prev = c
return out
def stats(cues, is_vtt=False):
if not cues:
return {}
total_chars = sum(len(visible(ln)) for c in cues for ln in c["lines"])
total_time = sum(max(c["end"] - c["start"], 0) for c in cues) / 1000
return {"cues": len(cues), "first": fmt(cues[0]["start"], is_vtt), "last_end": fmt(max(c["end"] for c in cues), is_vtt),
"avg_cps": round(total_chars / total_time, 1) if total_time else None,
"avg_duration_s": round(total_time / len(cues), 2)}
def shift_text(text, delta):
def rep(m):
g = m.groups()
vtt = "." in m.group(0).split("-->")[0]
a = max(to_ms(*g[0:4]) + delta, 0)
b = max(to_ms(*g[4:8]) + delta, 0)
return f"{fmt(a, vtt)} --> {fmt(b, vtt)}{g[8]}"
return "\n".join(TS.sub(rep, ln) if "-->" in ln else ln
for ln in text.replace("\r\n", "\n").split("\n"))
def main(argv):
opts = {"max_cps": 17.0, "max_line": 42, "max_lines": 2, "min_dur": 0.833, "max_dur": 7.0,
"min_gap": 83, "json": False, "fail_on": "high", "shift": None}
files = []
it = iter(argv)
try:
for a in it:
if a == "--json":
opts["json"] = True
elif a in ("--max-cps", "--min-dur", "--max-dur"):
opts[a[2:].replace("-", "_")] = float(next(it))
elif a in ("--max-line", "--max-lines", "--min-gap", "--shift"):
opts[a[2:].replace("-", "_")] = int(next(it))
elif a == "--fail-on":
opts["fail_on"] = next(it).lower()
if opts["fail_on"] not in LEVELS:
raise ValueError("--fail-on must be high, warn, or info")
elif a in ("-h", "--help"):
print(__doc__)
return 0
elif a.startswith("--"):
raise ValueError(f"unknown option {a}")
else:
files.append(a)
except (StopIteration, ValueError) as e:
print(f"error: {e or 'option needs a value'}", file=sys.stderr)
return 2
if not files:
print("error: give at least one .srt or .vtt file, or - for stdin", file=sys.stderr)
return 2
report, worst = [], -1
for f in files:
try:
text = sys.stdin.read() if f == "-" else open(f, encoding="utf-8-sig").read()
except (OSError, UnicodeDecodeError) as e:
print(f"error: cannot read {f}: {e}", file=sys.stderr)
return 2
if opts["shift"] is not None:
sys.stdout.write(shift_text(text, opts["shift"]))
return 0
cues, errors, is_vtt = parse(text)
if not cues:
print(f"error: {f}: no subtitle cues found (is this an SRT or WebVTT file?)", file=sys.stderr)
return 2
findings = check(cues, errors, opts, is_vtt)
for x in findings:
worst = max(worst, LEVELS[x["level"]])
report.append({"file": f, "format": "vtt" if is_vtt else "srt", "stats": stats(cues, is_vtt), "findings": findings})
if opts["json"]:
print(json.dumps(report, indent=2))
else:
for r in report:
counts = {lv: sum(1 for x in r["findings"] if x["level"] == lv) for lv in ("high", "warn", "info")}
st = r["stats"]
print(f"{r['file']} ({r['format'].upper()}): {st['cues']} cues, {st['first']} to {st['last_end']}, "
f"avg {st['avg_cps']} chars/s, avg {st['avg_duration_s']} s on screen")
print(f" HIGH {counts['high']} WARN {counts['warn']} INFO {counts['info']}")
for x in sorted(r["findings"], key=lambda x: (-LEVELS[x["level"]], x["line"])):
where = f"cue {x.get('cue', '-')} @ {x['time']}" if "time" in x else f"line {x['line']}"
print(f" {x['level'].upper():<4} {x['rule']:<16} {where}: {x['message']}")
if not r["findings"]:
print(" no problems found")
return 1 if worst >= LEVELS[opts["fail_on"]] else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))超写实四场万圣节恐怖短片:年轻女性在雾气公交站逃离女巫后,在烛光维多利亚宅中获善良老妇庇护,直到带同一银吊坠的 40 年前肖像揭示转折,含声音设计、角色一致性规则与负面提示。
场景 1 — 公交站(0–10 秒) 10 月 31 日万圣节之夜,年轻成年女性独自站在被浓雾、枯树与闪烁橙色万圣节南瓜包围的荒凉公交站。突然,可怕女巫出现在她身后,灰发狂乱、眼睛发光,颈间古董银吊坠。 女巫低语:「You shouldn't be alone on Halloween night!」女性转身尖叫,绝望跑入雾中。 场景 2 — 老宅(10–23 秒) 女性发现古老维多利亚宅并敲门。老妇热情开门邀请她进入。烛光房间舒适,有万圣节装饰、雕刻南瓜与旧壁炉。 老妇端上热汤与面包,温柔说:「Come in, dear. You're safe here tonight.」 受惊女性开始放松,外面雷声隆隆。 场景 3 — 惊人发现(23–38 秒) 进食时,女性注意到墙上旧肖像。画中美丽年轻女性佩戴与公交站可怕女巫完全相同的银吊坠。 她缓慢走近肖像,盯着熟悉面孔与相同项链。画下铭文写着:「OCTOBER 31 — 40 YEARS AGO。」 她脸色煞白。突然意识到肖像中的女人就是她在外面遇到的女巫。 她缓慢将头转向身后站立的老妇。 场景 4 — 最终惊吓 老妇以不自然险恶微笑盯着她。眼睛突然发黄,面孔变成可怕女巫的脸,爆发出令人毛骨悚然的狂笑。 相机迅速推向女巫恐怖面孔,闪电从窗闪过。 猛切至黑。 女巫邪恶笑声在黑暗中回响一次。 结束。 视觉风格:超写实真人实拍恐怖,电影感维多利亚宅,真实雾与雨,闪烁烛光,细节面部表情,实用超自然变形,戏剧阴影与强烈万圣节氛围。 声音设计:呼啸风、远处雷、脚步、吱呀门、诡异低语、突然变形音与恐怖女巫笑声。 角色一致性:全程保持同一年轻女性、同一老妇与相同银吊坠。女巫外观必须匹配肖像中变形前的年轻女性。 负面提示:无卡通、无动漫、无廉价 CGI、无不一致面孔、无服装更换、无字幕、无标志、无水印,最终黑屏后无更多场景。
九镜头、30 秒带时间戳提示词,伪造被遗忘的 1985 年 35mm 剑与魔法电影:傲慢皇帝饮下兜帽仆人的黑杯,宴会宾客竟是数世纪亡者,仆人揭面为骷髅收藏者,含旁白与对白台词、1980 年代实用特效外观、摄影与声音设计。
创作一部引人入胜的 30 秒黑暗奇幻影片,外观像被遗忘的 1985 年好莱坞剑与魔法电影,以真实 35mm 胶片拍摄,精巧实用生物特效、手工服装、戏剧表演与氛围摄影。 故事讲述冷酷皇帝在古老宫殿举办盛大宴会。他已征服七国,相信凡人无法挑战他。庆典中,神秘兜帽仆人呈上盛有奇异黑色液体的金杯。皇帝饮下以示无畏,但恐怖之事发生。席上每位宾客突然凝固,面孔缓缓转向他。皇帝意识到周围之人已死去数世纪,神秘仆人前来收取债务。 通过恰好九个电影感镜头讲述故事,含戏剧性特写、戏剧运镜、实用超自然特效与震惊最终揭示。整部影片保持在一个巨大中世纪王座大厅内,张力通过皇帝的傲慢、神秘金杯与宴会宾客的恐怖变形自然发展。 包含深沉不祥男性旁白以简短英文画外音,以及皇帝与神秘仆人的自然英文对白。所有可见对白须有富表现力表演与准确口型同步。 [2] 全局设定 整部影片发生在夜间巨大中世纪帝国王座大厅。巨大石柱支撑拱顶,巨大绯红旗帜挂在墙上,数百闪烁蜡烛照亮铺满金杯、烤肉、银盘与精巧仪式装饰的奢华宴会桌。厚重天鹅绒窗帘框住俯瞰月照王国的高耸窗户。 环境类似精心搭建的 1980 年代奇幻电影布景,实用烛光、浓厚大气薄雾、手工石建筑、绘制背景延伸与丰富戏剧布光。 皇帝:五十多岁威严成年男子,长银发、浓灰须、锐利蓝眼与傲慢威慑表情。佩戴镶红宝石的巨大镂刻金冠、精巧金色仪式盔甲与毛皮镶肩长绯红天鹅绒斗篷。声音深沉、有力、傲慢。 神秘仆人:高瘦不自然的身影,穿长黑兜帽袍配精巧古董刺绣。面部大多掩于兜帽下,露出苍白皮肤、凹陷眼睛与令人不安的表情。手持盛满浓稠黑色液体的古老金杯。动作不自然地平静从容,声音安静、空洞、神秘。 宴会宾客:贵族男女、骑士与皇家顾问,穿精巧中世纪服装、华丽珠宝、刺绣长裙与仪式盔甲。起初看起来鲜活欢快,随后以细节实用假体化妆揭示苍白腐朽面孔。变形保持非写实血腥,类似 1980 年代黑暗奇幻电影的戏剧性亡灵。 远古收藏者:神秘仆人的真实身份,结尾揭示为兜帽下超自然骷髅身影,琥珀发光眼,面孔以精巧机械骷髅假体构建。 摄影:真实 1980 年代 35mm 胶片摄影,复古变形镜头,温暖琥珀烛光,浓郁绯红与金色调色,深戏剧阴影,细微光化学颗粒,轻柔高光光晕,实体雾,精巧实用布景与戏剧奇幻构图。 声音:不祥管弦乐、中世纪宴会环境音、远处笑声、碰杯声、闪烁火焰、低超自然低语与清晰英文角色对白。 [3] 带时间戳分镜 镜头 1 | [00:00-00:03] 征服者 壮丽宽电影感镜头揭示皇帝坐在巨大宴会桌首,周围是欢笑贵族与装甲骑士。数百蜡烛在金盘与绯红旗帜间闪烁,仆人在拥挤大厅中走动。 相机缓慢推向皇帝,他将金杯举过头顶。 旁白(深沉不祥画外音):"He conquered seven kingdoms..." 切至镜头 2。 镜头 2 | [00:03-00:06] 皇帝的骄傲 戏剧性低角度特写捕捉皇帝在巨大金冠下傲慢大笑。银须捕捉温暖烛光,他将金杯砸向桌面,周围贵族陷入沉默。 皇帝(洪亮声音):"NOT EVEN DEATH CAN COMMAND ME!" 贵族以紧张笑声回应。 切至镜头 3。 镜头 3 | [00:06-00:09] 不速之客 缓慢跟拍揭示神秘兜帽仆人从两根巨大石柱间黑暗中走出。他走向皇帝桌前,手持盛满浓稠黑液的古董金杯。 周围宾客逐渐停止说话,仆人将金杯直接置于皇帝面前。 仆人(安静令人不安的声音):"Then drink, Your Majesty." 切至镜头 4。 镜头 4 | [00:09-00:12] 禁忌金杯 私密特写展示皇帝审视华丽金杯中的黑液。液面不自然移动,反射附近无人拥有的面孔。 皇帝冷笑,举起金杯,自信一饮而尽。 旁白(画外音):"But one debt remained unpaid." 皇帝放下空杯,微笑缓慢消退,宴会厅完全寂静。 切至镜头 5。 镜头 5 | [00:12-00:16] 沉默宴会 宽对称镜头揭示整张宴会桌冻结在不自然静止中。每位贵族、骑士与仆人都停止移动,表情锁在诡异微笑中。 宾客一个接一个完美同步地将头转向皇帝。 皇帝左右张望,突然害怕。 皇帝(困惑):"What is this?" 蜡烛剧烈闪烁,冷风穿过大厅。 切至镜头 6。 镜头 6 | [00:16-00:19] 死者记得 恐怖特写揭示坐在皇帝旁的年长贵族女。曾经美丽的面孔通过精巧实用化妆效果逐渐变成苍白古老尸体。脸颊凹陷,眼睛变暗,表情变成不自然微笑。 相机略移揭示其他宾客经历同样变形,华丽服装保持不变。 贵族女(低语):"We have waited so long..." 皇帝惊恐后退。 切至镜头 7。 镜头 7 | [00:19-00:23] 真相 戏剧性中景展示皇帝从王座起身,打翻椅子,盯着包围他的亡灵宾客。神秘仆人在桌对侧保持完全静止。 皇帝(愤怒又恐惧):"WHO ARE YOU?" 仆人缓慢抬起头,揭示兜帽下苍白空洞特征。 仆人(平静):"The one you promised your soul." 皇帝脸色煞白。 切至镜头 8。 镜头 8 | [00:23-00:27] 收藏者 戏剧性特写捕捉神秘仆人缓慢拉开兜帽。面孔通过精巧实用假体与机械面部效果变成古老骷髅生物。眼睛发暗琥珀光,周围蜡烛逐一熄灭。 亡灵宾客沉默从椅中起身,在皇帝周围形成静止圆圈。 旁白(深沉画外音):"And tonight... the collector returned." 骷髅身影向皇帝伸出一只长骨手。 切至镜头 9。 镜头 9 | [00:27-00:30] 最终偿还 极端特写捕捉皇帝惊恐面孔,他背靠巨大金王座。王冠滑向一侧,颤抖双手抓住扶手。 骷髅收藏者靠近,发光眼睛映在皇帝惊恐目光中。 收藏者(深沉低语):"Your throne is ready... below." 皇帝张口尖叫,王座厅陷入黑暗。 最终金属撞击声回荡大厅。 切至黑。 [4] 全局补充 九镜头结构:使用恰好九个电影感镜头,在指定时间戳刻意剪辑。每个镜头必须推进同一连续故事,从皇帝傲慢开始,引入神秘仆人,揭示诅咒宴会,以收藏者要求偿还结束。全程保持一致角色位置与王座厅地理。 旁白与对白:包含所有旁白台词与角色对白,精确如所写。旁白为深沉共鸣男声,灵感来自经典 1980 年代奇幻预告。皇帝以戏剧权威说话,仆人以令人不安的平静,亡灵贵族女以柔软空洞低语。所有说出的角色对白必须与可见口型准确同步。旁白保持画外,不得与重要对白重叠。 1980 年代实用特效:亡灵宾客必须类似演员佩戴精巧乳胶假体、戏剧尸体化妆与手工奇幻服装。收藏者骷髅变形必须类似真实 1980 年代奇幻制作的精巧机械生物特效,使用机械面部装置、实用化妆、光学叠化与受控戏剧布光。 角色一致性:全程保留皇帝银发、灰须、金冠、绯红斗篷与镂刻盔甲。神秘仆人必须保留黑兜帽袍与金杯直至最终揭示。所有宴会宾客必须保持既定位置,超自然变形期间服装不变。 视觉氛围:保持丰富烛光内景、深绯红旗帜、华丽金色装饰、大气烟雾、暖钨丝高光、深戏剧阴影、有机胶片颗粒、细微光晕与真实光化学柔和。变形序列应逐渐使大厅变暗,同时保留复古奇幻电影视觉外观。 运镜:使用缓慢戏剧推进、戏剧低角度构图、富表现力特写与精心取景的宽镜头。避免过度手持、现代无人机式摄影或不可能的相机路径。 声音设计:以热闹宴会环境音、碰杯、远处笑声与管弦中世纪音乐开始。诅咒激活时逐渐移除背景声,留下不自然寂静,被低语、吱呀椅与皇帝惊恐呼吸打破。最终时刻以不祥低弦与收藏者深沉声音推进,然后突然黑暗结束。
制作级 15 秒四镜头视频提示:老水手独自在寒冷北方水域黎明浓雾中划行,前方缓缓浮现约 140 米三桅黑帆盖伦,从侧面特写到两广角分层揭示以卖出巨大尺度。含连续性锚点、精确镜头时码与焦段、船帆雾物理规则、冷蓝调色、声音设计与避免事项。无战斗、无鬼魂、无对白。
[标题] 雾中黑帆 [整体方向] 一段 15 秒写实海上电影序列,16:9,以 2.39:1 宽银幕感受与自然 24fps 运动构图。序列包含四个独立镜头。 故事发生在中世纪寒冷的北欧水域。一位年迈的欧洲白人男子独自划着小木船进入浓雾,发现一艘远超寻常船只的黑帆海盗船。 序列聚焦于船只在雾中被逐渐揭示,以及脆弱小艇、老人与巨大海盗船之间极端的尺度反差。氛围寒冷、寂静、压抑,但没有超自然生物、鬼魂、魔法效果或战斗。 所有木材、帆布、绳索、海水、雾气与人体运动须有令人信服的重量与物理行为。画面应感觉像用全尺寸实景帆船、真实海洋与电影机拍摄——而非电子游戏过场或奇幻概念艺术。 [固定连续性锚点] 全程保持同一年迈白人男子、同一面容、同一破旧中世纪服装、同一四米深色木划艇、同一对木桨、同一三桅黑帆海盗船,以及同一片冷蓝雾海。 海盗船须保持在老人前方略偏右。船首以轻微角度面向划艇。船几乎静止,仅随长涌缓慢移动。划艇持续驶向海盗船。 风、浪与雾始终自画面左侧移向右侧。寒冷晨光始终来自左上方。 海盗船在每镜须保持恰好三根主桅、层叠黑帆、高艏楼与艉楼、长艏斜桁、深色木船体与密集索具。设计不得在剪辑间改变。 [老人外貌] 唯一角色是一位 74 岁欧洲白人男子。他瘦削略驼,但肩与臂仍保有一生体力劳动的精干力量。 苍白粗糙皮肤被寒风、海水与多年日晒深深刻印。颧骨突出,鼻梁高且略歪,眼睛深陷,面颊与下巴覆着不均灰白胡须。 眼睛灰蓝,自然湿润,有细小生动眼神光。前额、眼角与嘴边有真实年龄纹。灰白发及颈后,被海雾打湿,以旧皮绳松松束起。几缕湿发贴着太阳穴与耳际。 皮肤须保留毛孔、老年斑与皱纹。勿美化、磨皮或人为弄脏面部。 [老人服装] 老人穿着破损炭灰粗羊毛斗篷。边缘磨损,并以几处简单手缝补丁修补。海雾湿气使织物变暗。 斗篷下是脏灰白亚麻束腰外衣,领口宽松、袖口磨损。风化深棕皮带束在腰间。他穿深灰棕编织裤与开裂旧皮靴。 颈间系着一小段褪色深红棕羊毛。这条围巾是整幅冷蓝画面中唯一微弱的暖色点缀。 服装不得含有现代缝线、拉链、塑料、品牌、反光条或现代浮力设备。 [角色行为] 老人眼下目标是穿越雾海,弄清前方巨大阴影究竟是什么。障碍是浓雾与反复改变划艇方向的长涌。 他以老水手练就的节制划行。重心保持低,双脚稳踏船底。先是下背缓慢后仰,然后肩与臂将两支木桨拉向胸前。 左右臂力量略有差异。每一桨伴有自然呼吸、肩胛运动、桨架摩擦与船的前冲惯性。动作已不再轻盈,但仍老练高效。 当巨大木船体的低沉呻吟穿过雾气传来时,他正在进行的划桨逐渐放缓。左桨叶仍浸水产生阻力,右桨停在半空。海水自桨缘持续滴落。 他的目光先离开海面,移向上方阴影。他缓慢眨一次眼。然后下巴抬起,头跟随目光方向。双唇保持闭合,呼吸短暂停顿,双手抓紧桨柄。 他不喊叫也不逃离。确认雾中藏着巨大船只后,他调整坐姿,双脚撑稳,重新缓慢划向阴影。表演传达谨慎、疲惫与不可抗拒的求知欲——而非戏剧化恐惧。 [划艇] 约 4.2 米长的中世纪木划艇,由深色陈年橡木制成。板缝与木榫结构可信。大部分黑色防水焦油涂层已磨损,露出下方灰棕木纹。 舷缘显出多年使用痕迹。内部保持简陋,仅一卷旧麻绳。勿添加渔网、灯笼、桶、箱或装饰物。 两支木桨在整段序列中须保持相同尺寸、颜色、材质与位置。 船随约一至一米半高的长涌轻柔起伏横摇。须有令人信服的重量与惯性。船首破水产生少量暗色浪花。不得像轻玩具般漂浮或弹跳。 [巨型海盗船] 海盗船基于古老欧洲三桅盖伦结构,但远大于任何寻常历史船只:长约 140 米,最高桅约达 80 米。 尺度非凡,但其木材构造、结构荷载、索具连接与帆布运动须保持物理可信。 船体几乎黑色、严重风化的橡木。木材宽重,板缝可见,结构边缘有哑光铁加固。船首高耸前伸,压迫感沉重,末端为长而窄的艏斜桁。 船尾升起多层艉楼。船体两侧两排深色炮门,但不发射火炮。吃水线附近有盐渍、暗湿痕与少量海生物。船不腐烂也不发光。 三根高主桅挂多层方黑帆。帆布厚重陈旧,被风与盐损坏,自然撕裂边缘与可见修补。帆非纯黑,含深青灰、炭灰与风化棕的微妙层次。 密集麻质索具按真实帆船构造连接桅杆、帆桁、舷缘与帆角。 最高桅顶飞一面褪色小黑旗。仅有简单风化骨白骷髅交叉骨符号,无文字。 甲板上不见船员、火把或人工灯光。船感觉异常寂静,但完全实体不透明,永不透明或鬼魅。 [海洋、雾与色彩] 序列发生在黎明寒冷北方水域。海天边界几乎被厚重蓝灰海雾抹去。 雾须保持真实纵深: 老人与划艇在前景相对清晰。 数十米外水面失去对比。 中景仅见海盗船局部。 上桅与帆角再度没入雾中。 海水为低饱和石板蓝、深蓝灰与淡灰绿。浪峰不产生不自然亮白泡沫。 天空为淡冷蓝混珍珠白。海盗船近黑木配深青灰帆。老人褪色红棕围巾提供唯一极弱暖色点缀。 风缓慢将雾推过船体,使其固定结构分层显现。雾改变可见内容;船体本身永不变形。 雾不得表现得像快速移动烟雾,也不得使整幅画面均匀模糊。 [镜头一|0–3.5 秒|老人侧面特写] 65mm 电影镜头。相机浮于划艇左侧,略低于老人肩高,随同一海涌轻柔起伏。 老人侧面轮廓占画面左半。背景仅有失焦冷蓝海水与层叠雾。海盗船此时不得出现。 老人已在划桨中途。下背缓慢后移,双手将桨拉向身体。湿灰发贴面,粗羊毛斗篷对海风有微妙反应。 一道宽涌抬起木船,相机以克制、物理落地的运动随之升起。 一声遥远低沉的旧青铜船钟穿过雾气,随后是巨大木结构在海压下的深沉呻吟。 老人划桨动作逐渐停止。一桨叶仍浸水,另一停在半空。水自桨缘滴落。 他的目光先移向画面右上方。缓慢眨一次眼,然后逐渐抬头。 在抬头动作完全完成前直接切出。本镜勿揭示他所见之物。 [镜头二|3.5–10 秒|后方视角与雾中揭示] 切至 35mm 镜头的老人中广后视。相机靠近划艇船尾约肩高。 保持前一镜的船向、老人坐姿、浪向与冷光方向。 老人背对相机占画面下中央。雾中前方升起巨大暗影。 起初仅能分辨高耸船首与一条模糊竖桅线。随雾横向移动,三根巨桅、层叠黑帆、密集索具与抬高甲板结构逐渐可见。桅顶仍隐藏。 海盗船不得瞬间完全显现。结构保持固定;仅随雾掠过改变可见度。 短暂停顿后,老人恢复划桨。他降低重心,完成一记缓慢刻意的桨,再开始第二桨。 划艇随涌前进。每次船升上浪峰,船影显得更高。船落入浪谷时,海盗船下部被水与雾短暂遮挡。 老人继续前行时,船首、深色炮门与最低黑帆逐渐更清晰。 高空风使巨大黑帆以延迟沉重的方式鼓起又放松。索具略收紧又放松。不得剧烈摆荡。 海盗船几乎静止,以极慢速度迎涌前进。 [镜头三|10–12.5 秒|第一广角:船首压迫] 直接切至 28mm 镜头低水面广角,自左侧远处观察划艇。 前景为失焦深蓝浪峰。老人与划艇在中景。海盗船高耸船首、低层黑帆与雾罩桅杆主导背景。 划艇仅约占画面宽度 2%。老人更小,但炭灰斗篷与褪色红棕围巾保持一致。 海盗船船首如暗木悬崖自海升起。大船体板材、炮门与哑光铁加固提供可信尺度参照。 前景浪短暂遮住划艇下半。浪峰落下后,船与海盗船空间关系不变地再现。 船体位置、尺寸与结构保持稳定。上层黑帆与桅杆部分被蓝灰雾吞没。 本镜强调船首垂直高度与小艇对巨船的压迫距离。 [镜头四|12.5–15 秒|第二广角:完整尺度] 切至略抬高的远处极广角,50mm 长焦压缩空间深度。相机保持稳定,无快速航拍俯冲、环绕或旋转。 巨大三桅海盗船以正侧角度出现,主导画面中右。 大部分完整船体、长艏斜桁、高艉楼、三根主桅与层叠黑帆进入画面。下船体相对清晰,上桅与帆角在浓雾中淡入淡出。 最高桅顶黑海盗旗缓慢移动。 老人与小船保持在船前方略偏左,缩成冷蓝海上一个微小暗点。划艇继续随涌起伏,老人缓慢划行。 海盗船保持沉重、寂静、几乎不可移。 两船保持安全距离。不发生碰撞。 大片冷蓝水面与空雾环绕主体。地平线无陆地、无其他船只、无现代结构。 最终构图保持约半秒,使老人、小艇与巨大黑帆同框可见。 [剪辑逻辑] 序列含四镜与三次直接切换。 第一切:自老人侧面抬头切到自其身后所见的巨大船影。 第二切:自老人继续划桨切到低水面广角,揭示船首高度。 第三切:切到更远略抬高的极广角,揭示海盗船总长与周围海洋。 两广角用途不同: 第一广角建立船首垂直压迫。 第二广角揭示完整船体及船、海与划艇的最终尺度关系。 勿插入骷髅、火炮、眼睛、索具五金或海盗船员特写。 [摄影与影像质感] 35mm 院线发行拷贝观感:柔和片门边缘、中低微对比、细微略不均自然颗粒、层叠深蓝与炭黑、柔和高光滚降。 雾与镜头边缘轻微凝露是唯一主导影像瑕疵。勿同时叠加雨、尘、烟、火花或强镜头光晕。 相机保留少量海面运动与惯性,同时保持地平线大体稳定。 近景使用克制景深。远距对比经大气透视自然降低。 海盗船在雾中不得显得不自然锐利,但整幅画面也不得被均匀模糊滤镜覆盖。 [光照] 唯一主光源是自左上方透过云层漫射的寒冷黎明光。 淡银蓝轮廓光触及老人面部左侧、湿发、木桨与舷缘。 海盗船受光侧显低对比冷灰结构。背光侧落入深蓝黑,同时保留可读木材层次。 勿使用月光束、火把光、幽灵绿照明、魔法辉光、闪电或暖日落光。 [声音] 无对白、旁白或配乐。 声景由木桨入海、低沉排水、桨架摩擦、划艇木板吱呀、老人克制却吃力的呼吸、雾软化的风、一声遥远青铜船钟、巨大木船体在浪压下的深沉呻吟、索具收紧,以及黑帆缓慢鼓风组成。 钟声与木材呻吟在镜头一海盗船出现前即可听见。 镜头二揭示船只时,低沉木质共鸣扩大。 最后两广角中,海浪、风与大片静默再度主导声景。 [负面约束] 避免镜头间改变老人面部、年龄、肤色、胡须长度、发型、斗篷颜色、围巾或服装。勿使他突然变年轻。 避免现代服装、盔甲、贵族服饰、刻板海盗服装、现代救生衣、塑料、拉链、现代鞋、手表、火器或电子设备。 避免错误解剖、扭曲身体比例、多余手臂、多余手指、桨数量变化、手穿透桨柄、僵硬划桨、机械循环动作、滑动脚步、夸张尖叫、张嘴惊恐表情、戏剧化恐惧、英雄姿势、空洞眼睛或冻结眼睛。 避免改变划艇尺寸、颜色、设计或材质。勿把船变成现代救生艇、渔船、帆船或塑料船。 避免失重漂浮、突然侧移、剧烈弹跳、倾覆、进水、解体或与海盗船碰撞。 避免改变海盗船设计、长度、船体形状、船首、船尾或颜色。保持恰好三根主桅。勿让桅杆出现或消失。 避免改变黑帆颜色、帆布融化、混乱索具、船首船尾对调、移动炮门、集装箱、蒸汽机、现代马达、钢上层建筑或电灯。 避免卡通海盗船、主题乐园景点、微缩模型、塑料木纹、发光鬼船、透明船体、骷髅船员、鬼魂、僵尸、海怪、触手、飞船、魔法、绿色鬼火、燃烧船帆、炮战、爆炸或闪电。 避免雾在镜头间突然消失或变色。勿使雾表现得像快速烟雾。海盗船不得因雾掠过而变形。 避免海啸浪、垂直水墙、凝胶状水、织物状水、烟雾状水、改变浪向、突然日光变化、暖日落色或夜晚。 避免快剪、额外镜头、地点变化、时间跳跃、闪光转场、叠化、变形转场、相机瞬移、高速无人机俯冲、绕船旋转、突然变焦、推拉变焦、慢动作或变速。 避免电子游戏过场、奇幻概念艺术、海盗主题广告、全画面均匀锐度、过度锐化、过度磨皮、过饱和、商业青绿橙调色、霓虹、激光、装饰光束、过度镜头光晕、文字、字幕、品牌标志与现代水印。 允许最高桅顶的简单骷髅交叉骨海盗旗,但旗上勿放置任何可读文字。