mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-14 11:17:01 -04:00
The interface had no face for Arabic or Hebrew, so caption text, track and media names showed missing-glyph boxes in the Text panel and on the timeline while the Program monitor drew them. crates/ui-egui/src/rtl.rs adds the craft-fonts Arab / Hebr faces, else one installed face per script (Noto Sans Arabic, SF Arabic, Segoe UI...), as the last fallbacks of every UI font family, as cjk.rs does for Chinese. egui already shapes each font run with harfrust, so the letters join, but it lays runs out left to right with no bidi pass and multi-word Arabic read backwards. rtl::Lines lays captions out in reading order: lines are broken on the logical text as egui wraps it, each line is reordered with unicode-bidi (UAX #9, as crates/text does for titles) and every right-to-left word is its own layout section for egui's shaper. Caption blocks on the timeline and the Text panel caption list use it; a caption being edited keeps egui's logical order, since TextEdit places the caret by character index. Left-to-right text is laid out exactly as before.
83 lines
5.7 KiB
Markdown
83 lines
5.7 KiB
Markdown
# Captions
|
||
|
||
FilmCraft keeps captions on **caption tracks** in the sequence, shown in their own area above the
|
||
video tracks (as Premiere does). Caption tracks are saved in the `.fcproj` (project format
|
||
version 2; version 1 projects open with no caption tracks).
|
||
|
||
## Model
|
||
|
||
- **Caption track** (`CaptionTrack`, `crates/project/src/caption.rs`): name, format (`Subtitle`,
|
||
`CEA-608`, `CEA-708`, `Teletext`), language, output eye (shown in the Program monitor and
|
||
burned in on export), lock, sync lock, and a **track style**:
|
||
font size (pixels at 1080 lines, scaled to the frame), text colour, background box and its colour,
|
||
outline width and colour, alignment (left/centre/right), position (top/middle/bottom) and
|
||
margin (a fraction of the frame height, default 0.08; `captions.setStyle` clamps it to 0–0.45),
|
||
line spacing.
|
||
- **Caption**: in/out in exact `Tick`s, text (lines separated by `\n`; `<i>`, `<b>`, `<u>` kept
|
||
as written), optional speaker, and the WebVTT cue id and cue settings, kept for round trips.
|
||
Captions on a track never overlap.
|
||
|
||
## Files
|
||
|
||
| Format | Import | Export | Notes |
|
||
|---|---|---|---|
|
||
| SubRip `.srt` | ✓ | ✓ | Forgiving reader (BOM, UTF-16, Windows-1252, CRLF, missing indexes, `,`/`.` ms, missing hours). |
|
||
| WebVTT `.vtt` | ✓ | ✓ | Keeps cue ids, cue settings, `<v Speaker>`, STYLE/REGION/NOTE blocks. `line:N%` and `align:` are honoured when drawing. |
|
||
| Scenarist SCC `.scc` | ✓ | ✓ | CEA-608 at 29.97 fps. Reads pop-on, roll-up and paint-on; writes pop-on with drop-frame (default) or non-drop timecode. |
|
||
|
||
`File ▸ Import` (or dropping a file) recognises caption files by extension and content and adds a
|
||
new caption track to the open sequence (a sequence is created when none is open). Cue times are
|
||
snapped to the sequence's frames. `File ▸ Export ▸ Captions…` writes the chosen caption track in
|
||
the format given by the file extension (`.srt`, `.vtt`, `.scc`).
|
||
|
||
Details of each format and the SCC encoder are in [`crates/captions/README.md`](../crates/captions/README.md).
|
||
|
||
## Editing
|
||
|
||
| Command | Menu / shortcut | Params |
|
||
|---|---|---|
|
||
| `captions.newTrack` | Sequence ▸ Captions ▸ Add New Caption Track… (⌥⌘A) | `format`, `name`, `language` |
|
||
| `captions.add` | Sequence ▸ Captions ▸ Add Caption at Playhead (⌥⌘C) | `track`, `text`, `time`, `durationSeconds` (3) |
|
||
| `captions.next` / `captions.previous` | Sequence ▸ Captions ▸ Go to Next/Previous Caption Segment (⌥⌘↓/↑) | |
|
||
| `captions.showAll` / `captions.hideAll` | Sequence ▸ Captions | |
|
||
| `captions.split` | Text panel ✂ | `caption`, `time` (default: every caption under the playhead) |
|
||
| `captions.merge` | Text panel | `captions` (consecutive, one track) |
|
||
| `captions.setText` | Text panel text field | `caption`, `text`, `speaker` |
|
||
| `captions.setTimes` | Text panel in/out fields | `caption`, `start…`/`end…` (`Time` ticks, `Frame`, `Seconds`, `Timecode`) |
|
||
| `captions.trim` | drag a caption edge in the timeline | `caption`, `edge` (`in`/`out`), `delta` or `deltaFrames` |
|
||
| `captions.move` | drag a caption in the timeline | `captions`, `delta` or `deltaFrames` |
|
||
| `captions.delete` | Edit ▸ Clear / Ripple Delete with captions selected | `captions`, `ripple` |
|
||
| `captions.select`, `captions.goTo` | click / number button | `captions`, `add` / `caption` |
|
||
| `captions.setTrack` | caption track header (eye, lock) | `track`, `name`, `format`, `language`, `enabled`, `locked`, `syncLock` |
|
||
| `captions.setStyle` | Text panel style strip | `track`, `size`, `color`, `background`, `backgroundColor`, `outline`, `outlineColor`, `align`, `anchor`, `margin`, `lineSpacing`, `reset` |
|
||
| `captions.deleteTrack` | | `track` |
|
||
| `captions.import` / `captions.export` | File ▸ Export ▸ Captions… | `path`, `format`, `track`, `dropFrame` |
|
||
| `captions.list` | (query) | `track` — tracks, styles and captions with timecodes (a `track` that names no caption track is an error) |
|
||
|
||
Tracks are addressed by id or `"C1"`, `"C2"`… (top first). Edits are limited by neighbouring
|
||
captions and a one-frame minimum. Sync-locked caption tracks follow insert and extract edits on
|
||
the media tracks (a caption across an insert point is split). `Add Edit to All Tracks` (⇧⌘K)
|
||
also splits captions.
|
||
|
||
## Timeline and Text panel
|
||
|
||
- Caption rows: header with `C1…` badge, lock, output eye, name and format; caption blocks in
|
||
violet showing their text (Arabic and Hebrew in reading order from the block's right edge). Click selects (⌘/⇧ adds), drag moves, edge drag trims, double-click
|
||
opens the Text panel. Automation ids: `timeline.caption.<id>`,
|
||
`timeline.captionTrack.C1[.locked|.enabled]`.
|
||
- **Text panel ▸ Captions**: search, track picker (also creates tracks of each format), add /
|
||
split / merge / delete / export buttons, the list of segments with editable in/out timecodes
|
||
and text (committed when the field loses focus; Arabic and Hebrew show in reading order and are
|
||
edited in logical order while the field has focus), and the track style strip (size, colour, box,
|
||
alignment, position). Automation ids: `text.tab.Captions`, `text.captions.add|split|merge|delete|export|search|track`,
|
||
`text.captions.<id>.in|out|text|goto|row`, `text.captions.style.*`.
|
||
|
||
## Burn-in
|
||
|
||
The Program monitor shows the visible caption tracks. On export, `file.exportMedia`
|
||
`{"burnCaptions": true}` (Export mode: **Burn Captions Into Video**) draws them into every frame.
|
||
Captions are set in Inter SemiBold (OFL, bundled) by the text engine (`crates/text`: shaping,
|
||
kerning, bidi); italics/bold markup is not yet drawn differently. The captions of a nested sequence
|
||
are part of the nest's picture: they are drawn wherever the nest is shown, in the Program monitor
|
||
and in every export, whether or not the outer sequence shows or burns in its own.
|