diff --git a/.coderabbit.yaml b/.coderabbit.yaml
new file mode 100644
index 000000000..2408084cf
--- /dev/null
+++ b/.coderabbit.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
+reviews:
+ auto_review:
+ # Dependabot bumps are checked by CI; skip CodeRabbit reviews on them.
+ ignore_usernames:
+ - "dependabot[bot]"
diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md
index 5e047f909..b952a98bc 100644
--- a/ATTRIBUTION.md
+++ b/ATTRIBUTION.md
@@ -29,7 +29,7 @@ iconography, images or other Adobe assets; open licences only; every asset attri
| `docs/images/filmcraft-keyframes.png` | FilmCraft contributors | Original work: FilmCraft screenshot; frames from Night of the Living Dead (1968, public domain) | MIT OR Apache-2.0; film frames public domain |
| `docs/images/filmcraft-export.png` | FilmCraft contributors | Original work: FilmCraft screenshot; frame from Night of the Living Dead (1968, public domain) | MIT OR Apache-2.0; film frames public domain |
| `docs/images/filmcraft-assembly.png` | FilmCraft contributors | Original work: FilmCraft screenshot; frames from Carnival of Souls (1962), Night of the Living Dead (1968), thumbnails of all demo media | MIT OR Apache-2.0; film frames public domain |
-| `docs/images/filmcraft-lumetri.png` | FilmCraft contributors | Original work: FilmCraft UI crop (Lumetri Color panel) | MIT OR Apache-2.0 |
+| `docs/images/filmcraft-color-panel.png` | FilmCraft contributors | Original work: FilmCraft UI crop (color grading panel) | MIT OR Apache-2.0 |
| `docs/images/filmcraft-scopes.png` | FilmCraft contributors | Original work: FilmCraft UI crop (scopes of a Charade (1963) frame, public domain) | MIT OR Apache-2.0 |
| `docs/images/filmcraft-effects.png` | FilmCraft contributors | Original work: FilmCraft screenshot crop; NASA Earth Views (US Government work, public domain) | MIT OR Apache-2.0; footage public domain |
| `docs/images/filmcraft-timeline.png` | FilmCraft contributors | Original work: FilmCraft UI crop; thumbnails from Night of the Living Dead (1968) and Carnival of Souls (1962), CC0 Chopin waveform | MIT OR Apache-2.0; film frames public domain |
diff --git a/Cargo.lock b/Cargo.lock
index 43b781b41..2dd0090a9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1679,7 +1679,7 @@ dependencies = [
[[package]]
name = "filmcraft"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"arboard",
"chrono",
@@ -1712,7 +1712,7 @@ dependencies = [
[[package]]
name = "filmcraft-aac"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -1722,7 +1722,7 @@ dependencies = [
[[package]]
name = "filmcraft-ac3"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
"thiserror 2.0.21",
@@ -1730,7 +1730,7 @@ dependencies = [
[[package]]
name = "filmcraft-apv"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -1740,14 +1740,14 @@ dependencies = [
[[package]]
name = "filmcraft-audio-dsp"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
]
[[package]]
name = "filmcraft-automation"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"base64 0.22.1",
"filmcraft-engine",
@@ -1763,7 +1763,7 @@ dependencies = [
[[package]]
name = "filmcraft-av1"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -1774,21 +1774,21 @@ dependencies = [
[[package]]
name = "filmcraft-avi"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
]
[[package]]
name = "filmcraft-bitstream"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"proptest",
]
[[package]]
name = "filmcraft-captions"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"filmcraft-project",
@@ -1801,11 +1801,11 @@ dependencies = [
[[package]]
name = "filmcraft-cfb"
-version = "0.9.0"
+version = "0.10.0"
[[package]]
name = "filmcraft-cli"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-automation",
"filmcraft-codecs",
@@ -1827,7 +1827,7 @@ dependencies = [
[[package]]
name = "filmcraft-codecs"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-aac",
"filmcraft-ac3",
@@ -1865,7 +1865,7 @@ dependencies = [
[[package]]
name = "filmcraft-color"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"proptest",
"serde",
@@ -1873,7 +1873,7 @@ dependencies = [
[[package]]
name = "filmcraft-dng"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-dng",
"rayon",
@@ -1882,7 +1882,7 @@ dependencies = [
[[package]]
name = "filmcraft-dnx"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -1892,7 +1892,7 @@ dependencies = [
[[package]]
name = "filmcraft-edit"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-geom",
"filmcraft-media",
@@ -1905,7 +1905,7 @@ dependencies = [
[[package]]
name = "filmcraft-engine"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"craft-docpath",
"filmcraft-audio-dsp",
@@ -1940,7 +1940,7 @@ dependencies = [
[[package]]
name = "filmcraft-export"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-aac",
"filmcraft-apv",
@@ -1971,7 +1971,7 @@ dependencies = [
[[package]]
name = "filmcraft-flac"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -1980,7 +1980,7 @@ dependencies = [
[[package]]
name = "filmcraft-format"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-media",
"filmcraft-project",
@@ -1993,7 +1993,7 @@ dependencies = [
[[package]]
name = "filmcraft-frame"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"filmcraft-time",
@@ -2003,7 +2003,7 @@ dependencies = [
[[package]]
name = "filmcraft-geom"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"proptest",
"serde",
@@ -2011,7 +2011,7 @@ dependencies = [
[[package]]
name = "filmcraft-golden"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"filmcraft-frame",
@@ -2028,7 +2028,7 @@ dependencies = [
[[package]]
name = "filmcraft-gpu"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"filmcraft-export",
@@ -2047,7 +2047,7 @@ dependencies = [
[[package]]
name = "filmcraft-h264"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -2057,7 +2057,7 @@ dependencies = [
[[package]]
name = "filmcraft-h264enc"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -2067,7 +2067,7 @@ dependencies = [
[[package]]
name = "filmcraft-hevc"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -2077,7 +2077,7 @@ dependencies = [
[[package]]
name = "filmcraft-interchange"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-cfb",
"filmcraft-color",
@@ -2094,7 +2094,7 @@ dependencies = [
[[package]]
name = "filmcraft-isobmff"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -2105,7 +2105,7 @@ dependencies = [
[[package]]
name = "filmcraft-matroska"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
"serde_json",
@@ -2113,7 +2113,7 @@ dependencies = [
[[package]]
name = "filmcraft-media"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"filmcraft-dng",
@@ -2129,7 +2129,7 @@ dependencies = [
[[package]]
name = "filmcraft-mpa"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -2138,7 +2138,7 @@ dependencies = [
[[package]]
name = "filmcraft-mpeg2v"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
"rayon",
@@ -2147,7 +2147,7 @@ dependencies = [
[[package]]
name = "filmcraft-mpegts"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
"thiserror 2.0.21",
@@ -2155,28 +2155,28 @@ dependencies = [
[[package]]
name = "filmcraft-mxf"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
]
[[package]]
name = "filmcraft-ogg"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
]
[[package]]
name = "filmcraft-opus"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
]
[[package]]
name = "filmcraft-platform"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-codecs",
@@ -2202,7 +2202,7 @@ dependencies = [
[[package]]
name = "filmcraft-project"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"filmcraft-geom",
@@ -2216,7 +2216,7 @@ dependencies = [
[[package]]
name = "filmcraft-prores"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"filmcraft-testkit",
@@ -2226,7 +2226,7 @@ dependencies = [
[[package]]
name = "filmcraft-render"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-audio-dsp",
"filmcraft-captions",
@@ -2246,7 +2246,7 @@ dependencies = [
[[package]]
name = "filmcraft-scopes"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"serde",
@@ -2255,7 +2255,7 @@ dependencies = [
[[package]]
name = "filmcraft-speech"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"candle-core",
"candle-nn",
@@ -2273,14 +2273,14 @@ dependencies = [
[[package]]
name = "filmcraft-testkit"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"png",
]
[[package]]
name = "filmcraft-text"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-color",
"harfrust",
@@ -2292,7 +2292,7 @@ dependencies = [
[[package]]
name = "filmcraft-time"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"proptest",
"serde",
@@ -2300,7 +2300,7 @@ dependencies = [
[[package]]
name = "filmcraft-tts"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"candle-core",
"candle-nn",
@@ -2314,7 +2314,7 @@ dependencies = [
[[package]]
name = "filmcraft-tts-text"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"serde",
"thiserror 2.0.21",
@@ -2322,7 +2322,7 @@ dependencies = [
[[package]]
name = "filmcraft-ui-egui"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"cpu-time",
"craft-ui",
@@ -2361,14 +2361,14 @@ dependencies = [
[[package]]
name = "filmcraft-vp8"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "filmcraft-vp9"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-bitstream",
"rayon",
@@ -2377,7 +2377,7 @@ dependencies = [
[[package]]
name = "filmcraft-web"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"eframe",
"egui",
@@ -7402,7 +7402,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
[[package]]
name = "xtask"
-version = "0.9.0"
+version = "0.10.0"
dependencies = [
"filmcraft-testkit",
"serde_json",
diff --git a/Cargo.toml b/Cargo.toml
index 625558e91..46716a680 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ members = ["crates/*", "apps/*", "xtask"]
default-members = ["crates/*", "apps/*", "xtask"]
[workspace.package]
-version = "0.9.0"
+version = "0.10.0"
edition = "2024"
license = "MIT OR Apache-2.0"
rust-version = "1.95"
diff --git a/README.md b/README.md
index daff93b38..176ea82e9 100644
--- a/README.md
+++ b/README.md
@@ -11,19 +11,22 @@
- An open-source, clean-room take on the Adobe Premiere Pro workflow: native on macOS, Windows and Linux, and in the browser via WebAssembly.
+ An open-source, modern non-linear video editing workflow: native on macOS, Windows and Linux, and in the browser via WebAssembly.
By the ArtCraft team.
@@ -103,7 +106,7 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels,
-
- The Lumetri Color panel. Basic Correction, Color Wheels and every other section, each with its own on/off switch.
+
+ The color grading panel. Basic Correction, Color Wheels and every other section, each with its own on/off switch.
-
+
Scopes that tell the truth. The waveform and vectorscope are computed from the graded frame. All grading happens in linear light, in 32-bit float.
@@ -130,14 +133,14 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels,
## Effects and motion
-
+
NASA's Earth Views from the ISS with a look applied, and the Effects browser open on the dissolves.
-- **Premiere 26's full Video Effects bin (93 effects in 16 folders), the Legacy bin and the obsolete effects old projects use, plus around 30 transitions.** Blurs (Bokeh, Focus, Compound), keys (Ultra Key, Track Matte), distortions (Corner Pin, Turbulent Displace, Warp Stabilizer), Lights & Glows, Immersive Video (VR) effects on equirectangular footage, Posterize Time, Echo and more. Cross dissolve, dip to black or white, film dissolve, wipes, irises, pushes, slides, zooms, page peel, cube spin and more.
+- **A comprehensive Video Effects bin (over 90 effects across 16 categories), legacy effects, plus around 30 transitions.** Blurs (Bokeh, Focus, Compound), keys (Ultra Key, Track Matte), distortions (Corner Pin, Turbulent Displace, Warp Stabilizer), Lights & Glows, Immersive Video (VR) effects on equirectangular footage, Posterize Time, Echo and more. Cross dissolve, dip to black or white, film dissolve, wipes, irises, pushes, slides, zooms, page peel, cube spin and more.
- **Motion and opacity on every clip:** position, scale, rotation, anchor point and anti-flicker, plus 26 blend modes.
-- **Keyframes like Premiere's:** linear, Bezier, auto and continuous Bezier, hold, ease in and ease out. Effect Controls shows a keyframe lane for every parameter under a time ruler with the playhead's handle, and each animated parameter opens into **value and velocity graphs** with draggable influence handles. Effect Controls and the Properties panel share the keyframe navigator (◀ ◆ ▶): add or remove the keyframe at the playhead, step to the previous or next one.
+- **Advanced keyframing:** linear, Bezier, auto and continuous Bezier, hold, ease in and ease out. Effect Controls shows a keyframe lane for every parameter under a time ruler with the playhead's handle, and each animated parameter opens into **value and velocity graphs** with draggable influence handles. Effect Controls and the Properties panel share the keyframe navigator (◀ ◆ ▶): add or remove the keyframe at the playhead, step to the previous or next one.
- **A GPU compositor** built on wgpu (Metal, Vulkan, DirectX 12, WebGPU). It samples YUV straight from the decoder with footprint supersampling and blends in linear light. A CPU path renders the same frames, and the two are tested against each other.
@@ -179,7 +182,7 @@ No FFmpeg inside. The video codecs, AAC, Opus and the containers are our own Rus
| **VP9** | ✓ | | Profiles 0–3, 8/10/12-bit, 4:2:0 to 4:4:4, tiles and superframes; bit-exact on 50+ streams; in WebM/Matroska and MP4 |
| **Opus** | ✓ | | SILK, CELT, hybrid and multistream surround; range-exact on every RFC 8251 conformance vector; in WebM/Matroska and MP4 |
| **AV1** | ✓ | | Main profile, 8/10-bit 4:2:0 and monochrome, every coding tool incl. film grain, superres and spatial layers; bit-exact with libdav1d on the libaom vectors tested; in MP4 and WebM/Matroska |
-| **Avid DNxHD / DNxHR** | ✓ | ✓ | All SMPTE ST 2019-1 CIDs (LB to 444, 8/10/12-bit); export writes DNxHR in MOV |
+| **DNxHD / DNxHR** | ✓ | ✓ | All SMPTE ST 2019-1 CIDs (LB to 444, 8/10/12-bit); export writes DNxHR in MOV |
| **MJPEG, PCM** | ✓ | ✓ | |
| **MP3, FLAC, ALAC, Vorbis** | ✓ | | Via the [symphonia](https://github.com/pdeljanov/Symphonia) crate (MPL-2.0) for now, to be replaced by our own |
| **MP4 / MOV** | ✓ | ✓ | Fragmented MP4, edit lists, timecode tracks |
@@ -200,7 +203,7 @@ Also imported: MPEG-2 / MPEG-1 video, AC-3, MP2, MXF (OP1a / OP-Atom), MPEG tran
Export mode, set to write the trailer as H.264 MP4.
- **H.264 MP4 with AAC, using our own encoders.** A 6-second 960×540 render takes 1.3 seconds and decodes in ffmpeg without a single warning, with strict error detection on.
-- **Also:** Apple ProRes 422 HQ and Motion JPEG in QuickTime, MXF OP1a and Avid-style OP-Atom (DNxHR, ProRes or H.264 with PCM and start timecode), PNG sequences, animated GIF and WAV.
+- **Also:** Apple ProRes 422 HQ and Motion JPEG in QuickTime, MXF OP1a and standard OP-Atom (DNxHR, ProRes or H.264 with PCM and start timecode), PNG sequences, animated GIF and WAV.
- **Background jobs** with progress and cancel, so you keep editing while it renders.
- **Render previews:** the render bar marks segments green, yellow or red; rendered previews are cached by content, so an edit only invalidates what it touches and undo brings the green back.
@@ -210,11 +213,11 @@ Also imported: MPEG-2 / MPEG-1 video, AC-3, MP2, MXF (OP1a / OP-Atom), MPEG tran
Move timelines between FilmCraft and every other editor:
-- **Final Cut Pro 7 XML (xmeml):** the format Premiere and DaVinci Resolve exchange. It carries nested sequences, transitions, generators, Motion, Opacity, Time Remap and audio levels, with keyframes.
+- **FCP 7 XML (xmeml):** industry-standard timeline interchange format. It carries nested sequences, transitions, generators, Motion, Opacity, Time Remap and audio levels, with keyframes.
- **FCPXML 1.9–1.11:** the spine, connected clips as lanes, transitions, retiming and compound clips.
- **OpenTimelineIO:** the open interchange format of the film industry, round-tripping every FilmCraft detail through `metadata.filmcraft`.
- **CMX 3600 EDL:** the oldest format still in use, with drop-frame timecode, dissolves, wipes, speed changes (`M2`) and one EDL per track.
-- **AAF (Edit Protocol):** for Avid Media Composer and Pro Tools. Video and audio tracks, dissolves and dips, clip volume with keyframes, markers and source timecode; audio embedded or as separate WAV / AIFF files, trimmed with handles, with clip effects rendered in and broken out to mono, plus an optional video mixdown. Import reads AAF back, extracting embedded audio.
+- **AAF (Edit Protocol):** standard timeline and audio interchange format. Video and audio tracks, dissolves and dips, clip volume with keyframes, markers and source timecode; audio embedded or as separate WAV / AIFF files, trimmed with handles, with clip effects rendered in and broken out to mono, plus an optional video mixdown. Import reads AAF back, extracting embedded audio.
- **OMF 2.0:** the audio-post handoff: the audio tracks with crossfades and gain, sample-accurate, with the audio encapsulated or alongside.
Import merges the document's bins, media and sequences into your project as one undoable step, and links each media file it finds on disk.
@@ -223,7 +226,7 @@ Import merges the document's bins, media and sequences into your project as one
## Built for agents
-Every menu item, button, slider and drag in FilmCraft is a **command** with an id, typed parameters and an enabled state. There are more than 650 engine commands (`filmcraft-cli commands` lists them), with the rest of Premiere's catalogue on the way. The UI, the CLI, a JSON control channel and an **MCP server** all dispatch the same commands, so Claude or any agent can cut, trim, grade, mix and export exactly the way a person does. The UI can also be driven at the level of mouse and keyboard: every widget has an automation id, and agents can click, drag, type and take screenshots.
+Every menu item, button, slider and drag in FilmCraft is a **command** with an id, typed parameters and an enabled state. There are more than 650 engine commands (`filmcraft-cli commands` lists them), with more commands continuously added. The UI, the CLI, a JSON control channel and an **MCP server** all dispatch the same commands, so Claude or any agent can cut, trim, grade, mix and export exactly the way a person does. The UI can also be driven at the level of mouse and keyboard: every widget has an automation id, and agents can click, drag, type and take screenshots.
```jsonc
// over the control channel (JSON lines on TCP) or as MCP tool calls
@@ -277,22 +280,22 @@ The control protocol is documented in [docs/control-protocol.md](docs/control-pr
| [docs/project-files.md](docs/project-files.md) | `.fcproj` format, schema migrations, auto-save and crash recovery |
| [docs/graphics.md](docs/graphics.md) · [docs/captions.md](docs/captions.md) | Text engine, graphic clips and tools; caption tracks and formats |
| [ROADMAP.md](ROADMAP.md) | Stage, parity numbers, languages, what's next and the progress log |
-| [docs/target-app-parity.md](docs/target-app-parity.md) · [docs/gaps.md](docs/gaps.md) · [docs/roadmap.md](docs/roadmap.md) | Parity assessment against Premiere Pro, the ranked list of shortfalls, milestones and current focus |
+| [docs/target-app-parity.md](docs/target-app-parity.md) · [docs/gaps.md](docs/gaps.md) · [docs/roadmap.md](docs/roadmap.md) | Parity assessment, the ranked list of shortfalls, milestones and current focus |
| [docs/codec-parity.md](docs/codec-parity.md) · [docs/file-format-parity.md](docs/file-format-parity.md) · [docs/hardware-parity.md](docs/hardware-parity.md) · [docs/ui-parity.md](docs/ui-parity.md) · [docs/localization-parity.md](docs/localization-parity.md) | Parity checklists by dimension |
## Status
FilmCraft is young and moving fast. Editing, trimming, multicam, colour, keyframes, effects, titles, captions, mixing, codecs and export work today.
-FilmCraft is in **alpha**. We track two numbers ([docs/target-app-parity.md](docs/target-app-parity.md), re-measured 2026-10-10 against Premiere Pro 26.5.2):
+FilmCraft is in **alpha**. We track two numbers ([docs/target-app-parity.md](docs/target-app-parity.md), re-measured 2026-10-10):
-- **Feature breadth: ~86%.** Premiere Pro's menu items, effects, transitions, panels and formats that exist in FilmCraft (menus 92% and effects 100% measured).
-- **Ready for real work: ~56%.** Our honest estimate of how close FilmCraft is to replacing Premiere on real projects.
+- **Feature breadth: ~86%.** Professional NLE menu items, effects, transitions, panels and formats that exist in FilmCraft (menus 92% and effects 100% measured).
+- **Ready for real work: ~56%.** Our honest estimate of how close FilmCraft is to handling full production work on real projects.
The biggest gaps today:
-- **Speed on big footage.** Hardware decoding works on macOS and Windows, and for H.264 and HEVC on Linux (VA-API, or NVDEC with NVIDIA's driver; VP9 and AV1 decode in software there). Blend modes and the most common effects run on the GPU, but Lumetri, keys and export rendering still run on the CPU; H.264 encoding can use the hardware encoder on macOS and on Windows and Linux with an NVIDIA GPU (opt-in, Export ▸ Hardware encoding), and H.265 export is hardware-only on both (HDR sequences export Main 10 PQ / HLG with NVENC; VideoToolbox writes 8-bit SDR) ([#30](https://github.com/storytold/filmcraft/issues/30)).
-- **Premiere projects.** `.prproj` files can't be opened yet; bring sequences over as FCP7 XML, AAF or OTIO.
+- **Speed on big footage.** Hardware decoding works on macOS and Windows, and for H.264 and HEVC on Linux (VA-API, or NVDEC with NVIDIA's driver; VP9 and AV1 decode in software there). Blend modes and the most common effects run on the GPU, but color grading, keys and export rendering still run on the CPU; H.264 encoding can use the hardware encoder on macOS and on Windows and Linux with an NVIDIA GPU (opt-in, Export ▸ Hardware encoding), and H.265 export is hardware-only on both (HDR sequences export Main 10 PQ / HLG with NVENC; VideoToolbox writes 8-bit SDR) ([#30](https://github.com/storytold/filmcraft/issues/30)).
+- **Native `.prproj` project import.** `.prproj` files can't be opened yet; bring sequences over as FCP7 XML, AAF or OTIO.
- **No plugins.** No VST3 / Audio Units or OpenFX hosting.
- **Delivery codecs.** H.264 is our only software delivery-codec export; H.265 exports only through a hardware encoder (NVIDIA on Windows: Main 8-bit SDR and Main 10 HDR PQ / HLG; VideoToolbox on macOS: 8-bit Main, SDR); no AV1 export yet.
- **Real-world media and platforms.** Our decoders are bit-exact on conformance streams, but camera and phone files in the wild are less tested. Windows and Linux get far less testing than macOS.
@@ -455,15 +458,13 @@ with its author, source and license in [ATTRIBUTION.md](ATTRIBUTION.md). Builds
**Footage and music in the screenshots:** NASA's Apollo 11 film and television footage from [images.nasa.gov](https://images.nasa.gov) (launch, Launch Control Center, lunar surface and recovery) and the Apollo 11 air-to-ground voice transcript, all US Government works in the public domain (NASA does not endorse this project); *Night of the Living Dead* (1968), *Carnival of Souls* (1962) and *Charade* (1963), all in the US public domain; *Earth Views from the ISS* by NASA; Chopin's Nocturne Op. 48 No. 1 and Ballade No. 1, performed for Musopen and released under CC0. The media itself is not in this repository. Sources and details for every asset are in [ATTRIBUTION.md](ATTRIBUTION.md).
-FilmCraft is an independent implementation. It contains no Adobe code, icons, images, presets or LUTs, and no GPL or LGPL code; every icon is drawn in code and every asset is openly licensed and attributed ([AGENTS.md](AGENTS.md)), apart from the ArtCraft name and logos, which are trademarks of the ArtCraft Team used under [`docs/brand/LICENSE-brand.txt`](docs/brand/LICENSE-brand.txt). ffmpeg is used only as an external test oracle.
+FilmCraft is an independent implementation. It contains no proprietary code, icons, images, presets or LUTs, and no GPL or LGPL code; every icon is drawn in code and every asset is openly licensed and attributed ([AGENTS.md](AGENTS.md)), apart from the ArtCraft name and logos, which are trademarks of the ArtCraft Team used under [`docs/brand/LICENSE-brand.txt`](docs/brand/LICENSE-brand.txt). ffmpeg is used only as an external test oracle.
The ArtCraft name, wordmark and logos in [`docs/brand/`](docs/brand/) are trademarks of the
ArtCraft Team and are not covered by this license. They may be used only unmodified, and only as
part of this repository and FilmCraft, under [`docs/brand/LICENSE-brand.txt`](docs/brand/LICENSE-brand.txt).
Forks and modified versions must remove them.
-Adobe, Photoshop, Illustrator, Premiere Pro, Lightroom, Acrobat, After Effects and InDesign are trademarks or registered trademarks of Adobe Inc. in the United States and/or other countries. FilmCraft is an independent, open-source project and is not affiliated with, sponsored by or endorsed by Adobe Inc.; these names are used only to describe the workflows it is compatible with.
-
diff --git a/ROADMAP.md b/ROADMAP.md
index fd0af0037..31ec2d752 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -5,7 +5,7 @@
**Stage: alpha** · next: beta, ~19 points of ready-for-real-work and ~400–700 h away, plus opening Premiere's `.prproj` ([why](docs/target-app-parity.md#stage); passes the [core-workflow gate](docs/roadmap.md#alpha-gate))
-> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (language table: Czech, #1156; previously: German ships the menus, #630) · **Target:** Adobe Premiere Pro 2026 (26.5.2)
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (language table: Czech, #1156; previously: German covers the whole interface) · **Target:** Adobe Premiere Pro 2026 (26.5.2)
Progress toward parity with Adobe Premiere Pro. This page is the summary; the detail is in
[docs/target-app-parity.md](docs/target-app-parity.md) (assessment, methodology, calibration),
@@ -88,7 +88,7 @@ Premiere ships 10 interface languages. Measured from our catalogs (3,498 strings
| Korean | partial (whole interface; needs an installed Hangul font; native review welcome) | ~100% |
| Czech | partial (whole interface; native review needed) | 100% |
| Japanese | partial (whole interface) | 99.7% |
-| German | menus only (native-reviewed) | 10.6% |
+| German | partial (whole interface; menus native-reviewed, the rest welcome) | ~100% |
| Vietnamese | none | 0% |
Also shipped: Ukrainian (menus only, 10%). Detail: [docs/localization-parity.md](docs/localization-parity.md).
@@ -168,6 +168,7 @@ Ranked; detail and "done when" in [docs/roadmap.md](docs/roadmap.md) and [docs/g
| Date | Change | Summary |
|---|---|---|
| 2026-10-19 | minor | Language table: Czech (#1156, 100%) |
+| 2026-10-13 | minor | Language table: German covers the whole interface (~100%) |
| 2026-10-12 | trivial | Progress log: Transform shutter on adjustment layers (#1088) |
| 2026-10-11 | minor | Language table: German ships the menus (#630, 10.6%) |
| 2026-10-10 | minor | Readiness-by-audience table with hours to ~95% per audience |
diff --git a/crates/automation/src/server.rs b/crates/automation/src/server.rs
index 0aebbc31d..fad4e4192 100644
--- a/crates/automation/src/server.rs
+++ b/crates/automation/src/server.rs
@@ -278,9 +278,22 @@ impl FilmcraftMcp {
}
/// The project tree plus the active sequence (null when there is none).
+ ///
+ /// `project.inspect` and `sequence.inspect` are two separate calls (two lock scopes in
+ /// headless mode, two round trips to the app in bridge mode), so the active sequence can
+ /// change between them if another client, or the app's own UI, switches sequence tabs in
+ /// that window (#1477). Pinning `sequence.inspect` to the `activeSequence` id this
+ /// `project.inspect` just reported keeps the pair consistent: the returned `sequence`, when
+ /// not null, always describes the sequence the returned `project.activeSequence` names.
async fn document(&self) -> Result {
let project = self.run("project.inspect", json!({})).await?;
- let sequence = self.run("sequence.inspect", json!({})).await.ok();
+ // `ItemId` is a u64 (`item_p` parses the `item` param with `u64_p`): read it as one too,
+ // not `as_i64`, so an id above `i64::MAX` is still looked up instead of silently going null.
+ let active = project.get("activeSequence").and_then(Value::as_u64);
+ let sequence = match active {
+ Some(id) => self.run("sequence.inspect", json!({"item": id})).await.ok(),
+ None => None,
+ };
Ok(json!({"project": project, "sequence": sequence}))
}
@@ -998,4 +1011,73 @@ mod tests {
let r = m.render_frame(Parameters(RenderParams { seconds: Some(0.5), max_side: Some(64) })).await.unwrap();
assert_ne!(r.is_error, Some(true));
}
+
+ /// `doc_inspect` composes `project.inspect` and `sequence.inspect` as two separate round
+ /// trips to the app. If the active sequence changes between them (another client, or the
+ /// app's own UI, switching tabs in that window), an unscoped `sequence.inspect` answers for
+ /// whichever sequence is active *now*, not the one `project.inspect` just reported, so the
+ /// pair comes back inconsistent (#1477, reproduced with a real bridge client and a flipping
+ /// `sequence.open` in `race_test.py`: ~300/300 calls mismatched). Pinning the second call to
+ /// the id the first one reported keeps `sequence`, when not null, always describing the
+ /// sequence `project.activeSequence` names.
+ #[tokio::test]
+ async fn doc_inspect_pins_the_sequence_to_the_reported_active_id() {
+ use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
+ let addr = listener.local_addr().unwrap().to_string();
+ tokio::spawn(async move {
+ let (s, _) = listener.accept().await.unwrap();
+ let (r, mut w) = s.into_split();
+ let mut lines = tokio::io::BufReader::new(r).lines();
+ while let Ok(Some(line)) = lines.next_line().await {
+ let req: Value = serde_json::from_str(&line).unwrap();
+ let result = match req["params"]["command"].as_str().unwrap_or_default() {
+ "project.inspect" => json!({"activeSequence": 21}),
+ // The app's own active sequence has since moved on to 54; only an explicit
+ // `item` still gets 21's data (an unscoped call would wrongly answer for 54).
+ "sequence.inspect" => json!({"id": req["params"]["params"]["item"].as_i64().unwrap_or(54)}),
+ _ => Value::Null,
+ };
+ let line = format!("{}\n", json!({"id": req["id"], "ok": true, "result": result}));
+ w.write_all(line.as_bytes()).await.unwrap();
+ }
+ });
+ let m = FilmcraftMcp::bridge(&addr).unwrap();
+ let v = m.document().await.unwrap();
+ assert_eq!(v["project"]["activeSequence"], json!(21), "{v}");
+ assert_eq!(v["sequence"]["id"], json!(21), "sequence must describe the reported active id, not whatever is active now: {v}");
+ }
+
+ /// `activeSequence` is a `u64` (`ItemId`'s representation; `item_p` parses the `item` param
+ /// with `u64_p`), so an id above `i64::MAX` must still round-trip through `document()`:
+ /// reading it with `as_i64` would silently return `None` and make `sequence` go null instead
+ /// of inspecting the (valid) id project.inspect reported.
+ #[tokio::test]
+ async fn doc_inspect_handles_an_active_sequence_id_above_i64_max() {
+ use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
+ const HUGE: u64 = i64::MAX as u64 + 1;
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
+ let addr = listener.local_addr().unwrap().to_string();
+ tokio::spawn(async move {
+ let (s, _) = listener.accept().await.unwrap();
+ let (r, mut w) = s.into_split();
+ let mut lines = tokio::io::BufReader::new(r).lines();
+ while let Ok(Some(line)) = lines.next_line().await {
+ let req: Value = serde_json::from_str(&line).unwrap();
+ let result = match req["params"]["command"].as_str().unwrap_or_default() {
+ "project.inspect" => json!({"activeSequence": HUGE}),
+ // Echoes back whatever `item` it was actually asked for, so the test can
+ // check that `document()` asked for `HUGE` rather than nothing at all.
+ "sequence.inspect" => json!({"id": req["params"]["params"]["item"]}),
+ _ => Value::Null,
+ };
+ let line = format!("{}\n", json!({"id": req["id"], "ok": true, "result": result}));
+ w.write_all(line.as_bytes()).await.unwrap();
+ }
+ });
+ let m = FilmcraftMcp::bridge(&addr).unwrap();
+ let v = m.document().await.unwrap();
+ assert_eq!(v["project"]["activeSequence"].as_u64(), Some(HUGE), "{v}");
+ assert_eq!(v["sequence"]["id"].as_u64(), Some(HUGE), "an id above i64::MAX must still be inspected, not dropped to a null sequence: {v}");
+ }
}
diff --git a/crates/color/src/lut.rs b/crates/color/src/lut.rs
index 67590eb12..73879a5b0 100644
--- a/crates/color/src/lut.rs
+++ b/crates/color/src/lut.rs
@@ -308,7 +308,11 @@ impl Lut {
if let Some(sh) = &self.shaper {
let _ = writeln!(s, "LUT_1D_SIZE {}", sh.size());
if both {
- if sh.domain_min != [0.0; 3] || sh.domain_max != [1.0; 3] {
+ let uniform = sh.domain_min.iter().all(|v| *v == sh.domain_min[0]) && sh.domain_max.iter().all(|v| *v == sh.domain_max[0]);
+ if !uniform {
+ // with both tables, DOMAIN_MIN/DOMAIN_MAX belong to the shaper
+ write_domain(&mut s, sh.domain_min, sh.domain_max);
+ } else if sh.domain_min != [0.0; 3] || sh.domain_max != [1.0; 3] {
let _ = writeln!(s, "LUT_1D_INPUT_RANGE {} {}", sh.domain_min[0], sh.domain_max[0]);
}
} else {
@@ -650,4 +654,16 @@ mod tests {
let mesh257 = (0..257).map(|i| i.to_string()).collect::>().join(" ") + "\n";
assert!(Lut::parse_3dl(&mesh257).is_err());
}
+
+ #[test]
+ fn cube_shaper_per_channel_domain_round_trips() {
+ let mut text = String::from("LUT_1D_SIZE 2\nLUT_3D_SIZE 2\nDOMAIN_MAX 1 2 3\n");
+ for _ in 0..10 {
+ text.push_str("0 0 0\n");
+ }
+ let a = Lut::parse_cube(&text).unwrap();
+ assert_eq!(a.shaper.as_ref().unwrap().domain_max, [1.0, 2.0, 3.0]);
+ let b = Lut::parse_cube(&a.to_cube()).unwrap();
+ assert_eq!(b.shaper.unwrap().domain_max, [1.0, 2.0, 3.0]);
+ }
}
diff --git a/crates/engine/src/clip_ops_tests.rs b/crates/engine/src/clip_ops_tests.rs
index 262b1ec80..940c00af5 100644
--- a/crates/engine/src/clip_ops_tests.rs
+++ b/crates/engine/src/clip_ops_tests.rs
@@ -1059,3 +1059,26 @@ fn linked_rate_stretch_keeps_one_speed_when_a_neighbour_blocks_the_sound() {
assert!((pic.speed - sound.speed).abs() < 1e-12);
assert!((r["speed"].as_f64().unwrap() - 60.0 / 70.0).abs() < 1e-9);
}
+
+/// #2358: Toggle Animation on a parameter an older effect instance lacks (it was added to the
+/// effect later) creates it from its default and animates it, instead of "no such param".
+#[test]
+fn toggle_animation_creates_a_parameter_missing_from_an_older_instance() {
+ let mut s = crate::Session::default();
+ s.execute("file.openDemoProject", serde_json::json!({})).unwrap();
+ let seq = s.state.active_sequence.unwrap();
+ let clip = s.active_sequence().unwrap().video_tracks[0].items[0].id;
+ // an older project: Motion without its Rotation entry
+ {
+ let p = std::sync::Arc::make_mut(&mut s.project);
+ let q = p.sequence_mut(seq).unwrap();
+ let (_, it) = q.find_item_mut(clip).unwrap();
+ let m = it.effects.iter_mut().find(|e| e.effect == "motion").unwrap();
+ m.params.remove("rotation");
+ }
+ // `"mask": null` is no mask, as in effects.setParam
+ s.execute("effects.toggleAnimation", serde_json::json!({"clip": clip.0, "effect": "motion", "param": "rotation", "mask": null})).unwrap();
+ let it = s.active_sequence().unwrap().find_item(clip).unwrap().1.clone();
+ let rot = it.effect("motion").unwrap().param("rotation").unwrap();
+ assert!(rot.is_animated(), "the stopwatch is on");
+}
diff --git a/crates/engine/src/commands.rs b/crates/engine/src/commands.rs
index f7737f571..162fb18ca 100644
--- a/crates/engine/src/commands.rs
+++ b/crates/engine/src/commands.rs
@@ -2860,10 +2860,17 @@ fn build() -> Vec {
"Track Settings",
[],
None,
- r#"{"track":"V1"|id,"locked":bool?,"syncLock":bool?,"enabled":bool?,"muted":bool?,"solo":bool?,"name":str?,"volumeDb":f64?,"pan":f64?}"#,
+ r#"{"track":"V1"|id,"locked":bool?,"syncLock":bool?,"enabled":bool?,"muted":bool?,"solo":bool?,"name":str?,"volumeDb":f64?,"pan":f64?,"label":"Violet|Iris|…"|""|null?}"#,
has_seq,
|s, p| {
let tr = track_p(s, p, "track", "timeline.setTrack")?.ok_or_else(|| bad("timeline.setTrack", "need `track`"))?;
+ // colour label: a label name, or "" / "None" / null for no colour
+ let label = match p.get("label") {
+ None => None,
+ Some(Value::Null) => Some(None),
+ Some(Value::String(n)) if n.is_empty() || n.eq_ignore_ascii_case("none") => Some(None),
+ Some(v) => Some(Some(v.as_str().and_then(Label::from_name).ok_or_else(|| bad("timeline.setTrack", format!("unknown label {v}")))?)),
+ };
let p = p.clone();
s.edit_sequence("Track Settings", |q, _, _| {
let t = q.track_mut(tr).ok_or(filmcraft_edit::EditError::NoTrack(tr))?;
@@ -2891,6 +2898,9 @@ fn build() -> Vec {
if let Some(v) = f64_p(&p, "pan") {
t.pan = v.clamp(-100.0, 100.0);
}
+ if let Some(l) = label {
+ t.label = l;
+ }
Ok(())
})?;
Ok(Value::Null)
@@ -3111,6 +3121,14 @@ fn build() -> Vec {
_ => None,
}
.ok_or_else(|| bad("effects.toggleAnimation", "no such effect"))?;
+ // a parameter an older instance lacks (added to the effect later) starts from its
+ // default, as the UI shows it, without touching an existing one
+ if p.get("mask").is_none_or(Value::is_null)
+ && !e.params.contains_key(&pid)
+ && let Some(d) = e.def().and_then(|d| d.param(&pid))
+ {
+ e.params.insert(pid.clone(), filmcraft_project::Param::new(d.default.clone()));
+ }
crate::masks::target_param(e, p, &pid).ok_or_else(|| bad("effects.toggleAnimation", "no such param"))?.toggle_animation(mt);
Ok(())
})?;
@@ -4259,6 +4277,7 @@ pub fn inspect_sequence(s: &Session, id: ItemId, q: &filmcraft_project::Sequence
let tr = |t: &filmcraft_project::Track| {
json!({
"id": t.id.0, "name": t.name, "locked": t.locked, "syncLock": t.sync_lock, "enabled": t.enabled, "muted": t.muted, "solo": t.solo,
+ "label": t.label.map(|l| l.name()),
"items": t.items.iter().map(|i| json!({
"clip": i.id.0, "item": i.item.0, "name": i.name, "start": i.start.0, "duration": i.duration.0,
"startFrame": rate.frame_at(i.start), "durationFrames": rate.frame_at(i.duration), "sourceIn": i.source_in.0, "speed": i.speed, "reverse": i.reverse,
diff --git a/crates/engine/src/graphic_templates.rs b/crates/engine/src/graphic_templates.rs
index f5053756b..00b66c72f 100644
--- a/crates/engine/src/graphic_templates.rs
+++ b/crates/engine/src/graphic_templates.rs
@@ -775,7 +775,12 @@ fn set_char_style(s: &mut Session, p: &Value) -> Result {
};
let tl = s.playhead();
let (start, end) = (u64_p(p, "start").map(|v| v as usize), u64_p(p, "end").map(|v| v as usize));
- let runs = s.edit_sequence("Character Style", move |q, _, _| {
+ // A pointer gesture shares one undo step only within the same clip, layer and range.
+ let merge = bool_p(p, "merge").unwrap_or(false).then(|| format!("graphics.setCharStyle:{}:{ei}:{start:?}:{end:?}", clip.0));
+ if bool_p(p, "begin").unwrap_or(false) {
+ s.history.merge_key = None;
+ }
+ let runs = s.edit_sequence_as("Character Style", merge.as_deref(), move |q, _, _| {
let (_, it) = q.find_item_mut(clip).ok_or(filmcraft_edit::EditError::NoItem(clip))?;
let mt = it.source_time_at(tl.clamp(it.start, it.end() - Tick(1)));
let e = &mut it.effects[ei];
@@ -1217,7 +1222,7 @@ pub fn commands() -> Vec {
"graphics.setCharStyle",
"Character Style",
&[],
- r##"{"clip":id?,"layer":n|name?,"start":char=0,"end":char=len,"style":{"font":str,"fontStyle":str,"size":px,"color":"#rrggbb","bold":bool,"italic":bool,"underline":bool,"tracking":n,"baselineShift":px,"caps":"normal|all caps|small caps"},"clear":bool? (remove styles from the range)}"##,
+ r##"{"clip":id?,"layer":n|name?,"start":char=0,"end":char=len,"style":{"font":str,"fontStyle":str,"size":px,"color":"#rrggbb","bold":bool,"italic":bool,"underline":bool,"tracking":n,"baselineShift":px,"caps":"normal|all caps|small caps"},"clear":bool? (remove styles from the range),"merge":bool?,"begin":bool? (start a new undo gesture)}"##,
has_graphic,
set_char_style,
),
diff --git a/crates/engine/src/graphic_templates_tests.rs b/crates/engine/src/graphic_templates_tests.rs
index 98a55a588..e49c0ec8f 100644
--- a/crates/engine/src/graphic_templates_tests.rs
+++ b/crates/engine/src/graphic_templates_tests.rs
@@ -380,3 +380,52 @@ fn copy_paste_duplicates_a_graphic_clip() {
assert!((pasted[0].start.seconds() - 620.0).abs() < 0.05, "at the playhead: {:?}", pasted[0].start);
assert_eq!(texts(&s, pasted[0].id), vec!["Lyric".to_string()]);
}
+
+#[test]
+fn character_style_drag_merges_only_its_target_and_range() {
+ let mut s = demo("gt-char-drag");
+ let c = clip_of(&s.execute("graphics.newText", json!({"text":"Alpha Bravo"})).unwrap());
+ let before = s.project.clone();
+ let n = s.history.undo.len();
+ for i in 0..8 {
+ s.execute("graphics.setCharStyle", json!({"clip":c.0,"start":0,"end":5,"style":{"size":105+i*5},"merge":true,"begin":i==0})).unwrap();
+ }
+ assert_eq!(s.history.undo.len(), n + 1, "one drag, one undo step");
+ let after = s.project.clone();
+ s.execute("edit.undo", json!({})).unwrap();
+ assert_eq!(*s.project, *before);
+ s.execute("edit.redo", json!({})).unwrap();
+ assert_eq!(*s.project, *after);
+ s.execute("graphics.setCharStyle", json!({"clip":c.0,"start":0,"end":5,"style":{"size":150},"merge":true,"begin":true})).unwrap();
+ assert_eq!(s.history.undo.len(), n + 2, "a new gesture on the same range starts a new step");
+ s.execute("graphics.setCharStyle", json!({"clip":c.0,"start":6,"end":11,"style":{"size":160},"merge":true})).unwrap();
+ assert_eq!(s.history.undo.len(), n + 3, "another character range does not merge");
+ let before = s.project.clone();
+ assert!(s.execute("graphics.setCharStyle", json!({"clip":c.0,"start":3,"end":3,"style":{"size":170},"merge":true})).is_err());
+ assert_eq!(*s.project, *before);
+ assert_eq!(s.history.undo.len(), n + 3, "an invalid edit adds no undo step");
+}
+
+#[test]
+fn character_style_merge_preserves_default_calls_and_separate_clips() {
+ let mut s = demo("gt-char-merge-targets");
+ let a = clip_of(&s.execute("graphics.newText", json!({"text":"First", "newClip":true})).unwrap());
+ let b = clip_of(&s.execute("graphics.newText", json!({"text":"Other", "newClip":true})).unwrap());
+ assert_ne!(a, b);
+ let n = s.history.undo.len();
+ for c in [a, b] {
+ s.execute("graphics.setCharStyle", json!({"clip":c.0,"start":0,"end":5,"style":{"size":120},"merge":true})).unwrap();
+ }
+ assert_eq!(s.history.undo.len(), n + 2, "distinct clips do not merge");
+ for size in [130, 140] {
+ s.execute("graphics.setCharStyle", json!({"clip":b.0,"style":{"size":size}})).unwrap();
+ }
+ assert_eq!(s.history.undo.len(), n + 4, "default calls retain separate undo steps");
+ let added = s.execute("graphics.newText", json!({"clip":b.0,"text":"Layer"})).unwrap();
+ assert_eq!(clip_of(&added), b);
+ let n = s.history.undo.len();
+ for layer in [0, 1] {
+ s.execute("graphics.setCharStyle", json!({"clip":b.0,"layer":layer,"start":0,"end":5,"style":{"size":150},"merge":true})).unwrap();
+ }
+ assert_eq!(s.history.undo.len(), n + 2, "distinct layers do not merge");
+}
diff --git a/crates/engine/src/multicam.rs b/crates/engine/src/multicam.rs
index 66e36308f..6145bbbd3 100644
--- a/crates/engine/src/multicam.rs
+++ b/crates/engine/src/multicam.rs
@@ -243,17 +243,19 @@ fn can_synchronize(s: &Session) -> std::result::Result<(), String> {
if sel.len() < 2 { Err("select at least two clips to synchronize".into()) } else { Ok(()) }
}
fn has_items(s: &Session) -> std::result::Result<(), String> {
- if s.state.project_selection.iter().any(|i| sync::project_clip(&s.project, *i).is_some()) {
+ if selected_items(s).iter().any(|i| sync::project_clip(&s.project, *i).is_some()) {
Ok(())
} else {
- Err("select clips in the Project panel".into())
+ Err("select clips in the Project panel or the Timeline".into())
}
}
+/// Two clips or more: Merge Clips then opens its dialog, which says what is wrong with a
+/// selection it can't merge (two video clips, no audio clip) instead of a greyed-out menu item.
fn has_two_items(s: &Session) -> std::result::Result<(), String> {
- if s.state.project_selection.iter().filter(|i| sync::project_clip(&s.project, **i).is_some()).count() >= 2 {
+ if selected_items(s).iter().filter(|i| sync::project_clip(&s.project, **i).is_some()).count() >= 2 {
Ok(())
} else {
- Err("select a video clip and audio clips in the Project panel".into())
+ Err("select a video clip and audio clips in the Project panel or the Timeline".into())
}
}
@@ -262,10 +264,30 @@ fn has_two_items(s: &Session) -> std::result::Result<(), String> {
fn items_p(s: &Session, p: &Value) -> Vec {
match p.get("items").and_then(Value::as_array) {
Some(a) => a.iter().filter_map(|v| v.as_u64().map(ItemId)).collect(),
- None => s.state.project_selection.clone(),
+ None => selected_items(s),
}
}
+/// The items Merge Clips and Create Multi-Camera Source Sequence work on without `items`: the
+/// clips selected in the Project panel, or, with none there, the media of the clips selected in
+/// the Timeline (with their linked partners), once each in selection order (#1362).
+pub fn selected_items(s: &Session) -> Vec {
+ if s.state.project_selection.iter().any(|i| sync::project_clip(&s.project, *i).is_some()) {
+ return s.state.project_selection.clone();
+ }
+ let Some(q) = s.active_sequence() else { return Vec::new() };
+ let mut out = Vec::new();
+ for c in with_links(s, &s.state.selection) {
+ if let Some((_, it)) = q.find_item(c)
+ && sync::project_clip(&s.project, it.item).is_some()
+ && !out.contains(&it.item)
+ {
+ out.push(it.item);
+ }
+ }
+ out
+}
+
fn method_p(p: &Value, cmd: &str) -> Result {
Method::from_params(p).map_err(|e| bad(cmd, e))
}
diff --git a/crates/engine/src/multicam_tests.rs b/crates/engine/src/multicam_tests.rs
index 1a8c3528b..c9221726f 100644
--- a/crates/engine/src/multicam_tests.rs
+++ b/crates/engine/src/multicam_tests.rs
@@ -328,6 +328,59 @@ const H: u32 = 90;
/// Three 4-second cameras (different scenes, own audio), a multi-camera source sequence by In
/// points, and a sequence holding one multi-camera clip on V1/A1. Returns (session, camera items,
/// source sequence, edit sequence).
+/// #1362: with nothing selected in the Project panel, Create Multi-Camera Source Sequence and Merge
+/// Clips take the media of the clips selected in the Timeline.
+#[test]
+fn multicam_from_clips_selected_in_the_timeline() {
+ let dir = tmp_dir("mc-timeline");
+ let files: Vec = ["a.mov", "b.mov", "c.mov"].iter().map(|f| dir.join(f)).collect();
+ for (f, sc) in files.iter().zip([DemoScene::OceanSunset, DemoScene::CityNight, DemoScene::Aurora]) {
+ make_movie(f, sc, W, H, 48);
+ }
+ let mut s = Session::default();
+ let refs: Vec<&Path> = files.iter().map(|p| p.as_path()).collect();
+ let items = import(&mut s, &refs);
+ let mut p = (*s.project).clone();
+ let edit =
+ p.new_sequence("Edit", filmcraft_project::SequenceSettings { width: W, height: H, frame_rate: FrameRate::FPS_24, ..Default::default() }, 1, 1, None);
+ s.project = std::sync::Arc::new(p);
+ s.state.active_sequence = Some(edit);
+ for (k, item) in items.iter().enumerate() {
+ s.set_playhead(FrameRate::FPS_24.tick_of(k as i64 * 48));
+ s.execute("source.open", json!({"item": item.0})).unwrap();
+ s.execute("source.overwrite", json!({})).unwrap();
+ }
+ s.execute("project.select", json!({"items": []})).unwrap();
+ s.execute("timeline.select", json!({"clips": []})).unwrap();
+ assert!(!s.is_enabled("clip.createMulticam"), "nothing selected anywhere");
+ let clips: Vec = s.active_sequence().unwrap().video_tracks[0].items.iter().map(|c| c.id.0).collect();
+ assert_eq!(clips.len(), 3);
+ s.execute("timeline.select", json!({"clips": clips})).unwrap();
+ assert!(s.is_enabled("clip.createMulticam") && s.is_enabled("clip.mergeClips"));
+ // Merge Clips opens on them, and says why it can't merge three video clips
+ assert!(s.execute("clip.mergeClips", json!({"method": "in"})).unwrap_err().to_string().contains("one video clip"));
+ let r = s.execute("clip.createMulticam", json!({"method": "in"})).unwrap();
+ let src = ItemId(r["sequence"].as_u64().unwrap());
+ let cameras: Vec = s.project.sequence(src).unwrap().video_tracks.iter().filter_map(|t| t.items.first().map(|c| c.item)).collect();
+ assert_eq!(cameras, items, "one camera per selected clip's media, in selection order");
+
+ // one video clip and an audio-only one, selected in the Timeline: Merge Clips takes them
+ s.state.active_sequence = Some(edit);
+ let wav = dir.join("room.wav");
+ std::fs::write(&wav, crate::voiceover::write_wav_f32(&vec![0.0; 48_000 * 2], 48_000)).unwrap();
+ let audio = import(&mut s, &[wav.as_path()])[0];
+ s.set_playhead(FrameRate::FPS_24.tick_of(200));
+ s.execute("source.open", json!({"item": audio.0})).unwrap();
+ s.execute("source.overwrite", json!({})).unwrap();
+ let q = s.active_sequence().unwrap();
+ let a = q.audio_tracks.iter().flat_map(|t| &t.items).find(|c| c.item == audio).unwrap().id.0;
+ s.execute("project.select", json!({"items": []})).unwrap();
+ s.execute("timeline.select", json!({"clips": [clips[0], a], "linked": false})).unwrap();
+ assert!(s.is_enabled("clip.mergeClips"));
+ let r = s.execute("clip.mergeClips", json!({"method": "in"})).unwrap();
+ assert!(r["item"].as_u64().is_some(), "{r}");
+}
+
fn mc_session(audio: &str) -> (Session, Vec, ItemId, ItemId) {
let dir = tmp_dir("mc-edit");
let files: Vec = ["a.mov", "b.mov", "c.mov"].iter().map(|f| dir.join(f)).collect();
diff --git a/crates/engine/src/previews.rs b/crates/engine/src/previews.rs
index 5b75c02f4..859ba1bb9 100644
--- a/crates/engine/src/previews.rs
+++ b/crates/engine/src/previews.rs
@@ -535,8 +535,7 @@ impl PreviewStore {
}
}
let path = self.dir()?.join(name);
- let bytes = std::fs::read(&path).ok()?;
- let src = pool.open_bytes(name, bytes.into()).ok()?;
+ let src = open_preview_file(pool, name, &path)?;
let mut g = self.sources.lock().unwrap_or_else(|e| e.into_inner());
g.push((name.to_string(), src.clone()));
if g.len() > 6 {
@@ -546,6 +545,21 @@ impl PreviewStore {
}
}
+/// Open a rendered preview file. Native builds read it in place (the container's index now,
+/// frames on demand): previews are full-resolution ProRes, gigabytes a minute, and reading each
+/// one whole filled memory during render and playback (#2185).
+#[cfg(any(unix, windows))]
+pub(crate) fn open_preview_file(_pool: &MediaPool, name: &str, path: &std::path::Path) -> Option {
+ let reader = filmcraft_media::reader::FileReader::open(path).ok()?;
+ filmcraft_media::reader::open_reader_within(name, std::sync::Arc::new(reader), &filmcraft_codecs::reader_openers(), &[], 0).ok()
+}
+
+#[cfg(not(any(unix, windows)))]
+pub(crate) fn open_preview_file(pool: &MediaPool, name: &str, path: &std::path::Path) -> Option {
+ let bytes = std::fs::read(path).ok()?;
+ pool.open_bytes(name, bytes.into()).ok()
+}
+
fn need_state(seg: &Segment) -> BarState {
match seg.need {
Need::None => BarState::None,
@@ -639,7 +653,6 @@ pub fn render(s: &mut Session, mode: RenderMode, p: &Value) -> Result {
let provider = s.media.full_res_provider(project.clone(), s.services.clone());
let (prog, res) = (job.progress.clone(), job.result.clone());
let nseg = todo.len();
- let pool = s.media.clone();
let run = move || {
let t0 = web_time::Instant::now();
let mut bytes = 0u64;
@@ -679,8 +692,6 @@ pub fn render(s: &mut Session, mode: RenderMode, p: &Value) -> Result {
break;
}
store.add_video(&name);
- // open it now so the first playback doesn't wait for the file read
- let _ = store.open(&pool, &name);
}
Err(e) => {
let _ = std::fs::remove_file(&part);
diff --git a/crates/engine/src/previews_tests.rs b/crates/engine/src/previews_tests.rs
index dfc6b7a48..95c6289c2 100644
--- a/crates/engine/src/previews_tests.rs
+++ b/crates/engine/src/previews_tests.rs
@@ -282,3 +282,29 @@ fn float_wav_round_trip() {
fn bar_state_serializes_lowercase() {
assert_eq!(serde_json::to_value(BarState::Green).unwrap(), json!("green"));
}
+
+/// #2185: preview files are read in place, never whole. Rendered previews still play from their
+/// files, and a file only a whole-file reader could open is refused rather than loaded.
+#[test]
+fn preview_files_are_streamed_not_read_whole() {
+ let (mut s, _) = session("stream");
+ let v = s.execute("sequence.renderEffectsInToOut", json!({"wait": true})).unwrap();
+ job_ok(&s, &v);
+ let seq = s.state.active_sequence.unwrap();
+ assert!(s.previews.frame(&s.media, &s.project, seq, 5, 1.0).is_some(), "a rendered frame plays from its file");
+ // a still image opens only from its whole bytes: as a preview file it is not opened
+ let dir = s.previews.dir().unwrap();
+ let png = dir.join("still.png");
+ // a 1×1 PNG
+ const PNG: &[u8] = &[
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 13, 73, 68, 65, 84,
+ 120, 218, 99, 100, 96, 248, 95, 15, 0, 2, 135, 1, 128, 235, 71, 186, 146, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130,
+ ];
+ std::fs::write(&png, PNG).unwrap();
+ assert!(s.media.open_bytes("still.png", PNG.into()).is_ok(), "the image opens from its bytes");
+ // (the web, without a file reader, still reads preview files whole)
+ if cfg!(any(unix, windows)) {
+ assert!(crate::previews::open_preview_file(&s.media, "still.png", &png).is_none());
+ }
+ let _ = std::fs::remove_dir_all(dir);
+}
diff --git a/crates/engine/src/settings.rs b/crates/engine/src/settings.rs
index 4ae4ec645..e4e2de1cf 100644
--- a/crates/engine/src/settings.rs
+++ b/crates/engine/src/settings.rs
@@ -109,6 +109,9 @@ pub struct AppearancePrefs {
/// "UI Scale": `auto` (default: the scale the operating system reports) or a fixed
/// percentage of [`UI_SCALES`] (`100` = one point per physical pixel).
pub ui_scale: String,
+ /// "Animate zoom, scrolling and menus" (#2325): off, the Timeline zooms and scrolls in one
+ /// step and menus, collapsing sections and tooltips appear without a fade.
+ pub animations: bool,
}
impl Default for AppearancePrefs {
@@ -122,6 +125,7 @@ impl Default for AppearancePrefs {
accessible_contrast: false,
highlight_color: DEFAULT_HIGHLIGHT.into(),
ui_scale: "auto".into(),
+ animations: true,
}
}
}
@@ -1054,6 +1058,7 @@ static CATEGORIES: &[Category] = &[
b("appearance.accessibleContrast", "Accessible color contrast", true),
f("appearance.highlightColor", "Highlight Color", Kind::Color, true),
f("appearance.uiScale", "UI Scale", Kind::Choice(UI_SCALES), true),
+ b("appearance.animations", "Animate zoom, scrolling and menus", true),
],
},
Category {
diff --git a/crates/engine/src/track_params_tests.rs b/crates/engine/src/track_params_tests.rs
index 6c243dfa5..707ad38cc 100644
--- a/crates/engine/src/track_params_tests.rs
+++ b/crates/engine/src/track_params_tests.rs
@@ -114,3 +114,38 @@ fn place_on_an_audio_track_places_the_sound_there_and_nothing_else() {
s.execute("timeline.place", json!({"item": with_picture.0, "seconds": 600.0})).unwrap();
assert_eq!(counts(&s), [2, 1, 2, 2]);
}
+
+/// Track colour labels (#1186): set, shown by `sequence.inspect`, saved with the project,
+/// cleared with "" / null, one undo step each; unknown names are refused.
+#[test]
+fn a_track_carries_a_colour_label() {
+ let mut s = demo();
+ let label = |s: &mut Session, kind: &str| s.execute("sequence.inspect", json!({})).unwrap()[kind][0]["label"].clone();
+ assert_eq!(label(&mut s, "video"), json!(null));
+ s.execute("timeline.setTrack", json!({"track": "V1", "label": "Forest"})).unwrap();
+ s.execute("timeline.setTrack", json!({"track": "A1", "label": "Mango"})).unwrap();
+ assert_eq!(label(&mut s, "video"), json!("Forest"));
+ assert_eq!(label(&mut s, "audio"), json!("Mango"));
+ // saved with the project, and a project from before the field still loads
+ let text = serde_json::to_string(&*s.project).unwrap();
+ let back: filmcraft_project::Project = serde_json::from_str(&text).unwrap();
+ let q = back.sequence(s.state.active_sequence.unwrap()).unwrap();
+ assert_eq!(q.video_tracks[0].label, Some(filmcraft_project::Label::Forest));
+ let mut old = serde_json::to_value(&q.video_tracks[0]).unwrap();
+ old.as_object_mut().unwrap().remove("label");
+ let old: filmcraft_project::Track = serde_json::from_value(old).unwrap();
+ assert_eq!(old.label, None);
+ // a plain track does not write the key at all
+ assert!(serde_json::to_value(&q.video_tracks[1]).unwrap().get("label").is_none());
+ // clear, undo, refuse
+ s.execute("timeline.setTrack", json!({"track": "V1", "label": ""})).unwrap();
+ assert_eq!(label(&mut s, "video"), json!(null));
+ s.execute("edit.undo", json!({})).unwrap();
+ assert_eq!(label(&mut s, "video"), json!("Forest"));
+ s.execute("timeline.setTrack", json!({"track": "V1", "label": null})).unwrap();
+ assert_eq!(label(&mut s, "video"), json!(null));
+ assert!(matches!(s.execute("timeline.setTrack", json!({"track": "V1", "label": "Chartreuse"})), Err(EngineError::BadParams { .. })));
+ // other settings leave the label alone
+ s.execute("timeline.setTrack", json!({"track": "A1", "muted": true})).unwrap();
+ assert_eq!(label(&mut s, "audio"), json!("Mango"));
+}
diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs
index fb55786db..5d95c5b80 100644
--- a/crates/project/src/lib.rs
+++ b/crates/project/src/lib.rs
@@ -760,6 +760,9 @@ pub struct Track {
/// Audio Track Mixer state: automation mode and lanes, sends, output, record arm.
#[serde(default)]
pub mixer: MixerStrip,
+ /// Colour label tinting the track's header and lane background (`None` = no colour).
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub label: Option,
}
impl Track {
@@ -780,6 +783,7 @@ impl Track {
pan: 0.0,
effects: Vec::new(),
mixer: MixerStrip::default(),
+ label: None,
}
}
pub fn end(&self) -> Tick {
diff --git a/crates/time/src/lib.rs b/crates/time/src/lib.rs
index 23f328bf5..2cb8004a8 100644
--- a/crates/time/src/lib.rs
+++ b/crates/time/src/lib.rs
@@ -416,11 +416,18 @@ pub fn format_time(t: Tick, rate: FrameRate, drop_frame: bool, display: TimeDisp
format!("{}{}+{:02}", if neg { "-" } else { "" }, a / per_ft, a % per_ft)
}
TimeDisplay::AudioSamples => {
- let secs = t.0.div_euclid(TICKS_PER_SECOND);
- let rem = Tick(t.0.rem_euclid(TICKS_PER_SECOND)).to_units_floor(sample_rate);
- format!("{:02}:{:02}:{:02}:{rem:05}", secs / 3600, (secs / 60) % 60, secs % 60)
+ let neg = t.0 < 0;
+ let a = t.0.unsigned_abs();
+ let tps = TICKS_PER_SECOND.unsigned_abs();
+ let secs = a / tps;
+ let rem = Tick((a % tps) as i64).to_units_floor(sample_rate);
+ format!("{}{:02}:{:02}:{:02}:{rem:05}", if neg { "-" } else { "" }, secs / 3600, (secs / 60) % 60, secs % 60)
+ }
+ TimeDisplay::Seconds => {
+ let s = format!("{:.3}", t.seconds());
+ // A tiny negative time rounds to zero but keeps its sign: drop it.
+ if s == "-0.000" { "0.000".to_string() } else { s }
}
- TimeDisplay::Seconds => format!("{:.3}", t.seconds()),
}
}
@@ -507,6 +514,24 @@ mod tests {
use super::*;
use proptest::prelude::*;
+ #[test]
+ fn seconds_display_has_no_negative_zero() {
+ let f = |t: i64| format_time(Tick(t), FrameRate::default(), false, TimeDisplay::Seconds, 48000);
+ assert_eq!(f(-1), "0.000");
+ assert_eq!(f(-2), "0.000");
+ assert_eq!(f(-(TICKS_PER_SECOND / 2500)), "0.000");
+ assert_eq!(f(-TICKS_PER_SECOND), "-1.000");
+ assert_eq!(f(-TICKS_PER_SECOND / 1000), "-0.001");
+ }
+
+ #[test]
+ fn audio_samples_negative_time_has_leading_minus() {
+ let r = FrameRate::new(30000, 1001);
+ let f = |t| format_time(Tick(t), r, false, TimeDisplay::AudioSamples, 48000);
+ assert_eq!(f(-TICKS_PER_SECOND), "-00:00:01:00000");
+ assert_eq!(f(-(TICKS_PER_SECOND + TICKS_PER_SECOND / 2)), "-00:00:01:24000");
+ }
+
/// Damaged files and projects can carry zero / negative rates and timebases, and users or
/// agents can type huge timecodes: these used to panic (division by zero, overflow,
/// crossed `clamp` bounds).
diff --git a/crates/ui-egui/README.md b/crates/ui-egui/README.md
index 108c36527..faefbf7f7 100644
--- a/crates/ui-egui/README.md
+++ b/crates/ui-egui/README.md
@@ -18,8 +18,8 @@ the committed span and undo. Set `FILMCRAFT_UI_SNAPSHOT_DIR` to render screensho
## Localisation
Edit > Language offers English, Japanese, Spanish, Brazilian Portuguese, Ukrainian, Simplified
-Chinese, German, Russian, French, Indonesian, Korean, Italian and Czech (which cover the whole interface).
-The language is stored in the engine's `general.interfaceLanguage` preference,
+Chinese, German, Russian, French, Indonesian, Korean, Italian and Czech (all but Ukrainian and Russian
+cover the whole interface; those two cover the core menus). The language is stored in the engine's `general.interfaceLanguage` preference,
restored on startup, and also available in Settings > General.
Its default, System Language (`system`), follows the operating system: the first of the user's
preferred languages that the interface has (the host supplies them through
@@ -33,11 +33,10 @@ fills translated templates, and `i18n::t` translates names from registries. Plac
(including user filenames containing braces) are inserted literally. Catalog translations are
original work using ordinary language, without proprietary localisation resources.
-Spanish, Japanese, Simplified Chinese, French and Brazilian Portuguese cover menus, panels, dialogs, settings and registry labels. Searches accept both the
+Spanish, Japanese, Simplified Chinese, French, Brazilian Portuguese and German cover menus, panels, dialogs, settings and registry labels. Searches accept both the
translated label and its English source, including Unicode capitals. Project content, command ids
and preference values retain their original values. Engine errors, CLI and MCP messages remain
-English. Ukrainian and Russian currently cover the core menus, German every menu; they fall back
-to English elsewhere.
+English. Ukrainian and Russian currently cover the core menus; they fall back to English elsewhere.
Verification: `cargo test -p filmcraft-ui-egui` checks catalog syntax, duplicate keys, placeholders,
literal/menu/registry coverage and UI behaviour; `cargo xtask ci` runs the workspace gates. Visual
diff --git a/crates/ui-egui/src/dock_ui.rs b/crates/ui-egui/src/dock_ui.rs
index 26b30601a..98951de89 100644
--- a/crates/ui-egui/src/dock_ui.rs
+++ b/crates/ui-egui/src/dock_ui.rs
@@ -97,6 +97,11 @@ impl FilmcraftApp {
Action::Activate { panel } => Some(*panel),
_ => None,
};
+ // a panel closed while floating remembers where; closed while docked, it forgets (#1985)
+ let closing = match &action {
+ Action::Close { panel } => Some((*panel, self.ui.floating.iter().find(|g| g.panels.contains(panel)).map(|g| g.rect))),
+ _ => None,
+ };
self.commit_dock(|shared| {
crate::dock_shared::check_last_docked(shared, &action)?;
shared.apply(action).map_err(|error| error.to_string())
@@ -104,6 +109,12 @@ impl FilmcraftApp {
if let Some(panel) = reveal {
self.pending_panel_raise = Some(panel);
}
+ if let Some((panel, rect)) = closing {
+ self.ui.closed_floating.retain(|(p, _)| *p != panel);
+ if let Some(rect) = rect {
+ self.ui.closed_floating.push((panel, rect));
+ }
+ }
if relocating
|| self.ui.keys.maximized.is_some_and(|panel| !self.ui.dock.contains(panel) && !self.ui.floating.iter().any(|group| group.panels.contains(&panel)))
{
diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv
index bbd437424..76991909c 100644
--- a/crates/ui-egui/src/i18n/de.tsv
+++ b/crates/ui-egui/src/i18n/de.tsv
@@ -5,13 +5,19 @@
# was consulted or copied; add entries the same way. Like the German catalogs of the other Craft
# apps, text addresses the user informally ("du") and commands use the infinitive ("Projekt
# öffnen…"). Product, format and feature names (FilmCraft, ArtCraft, Lumetri, Essential Graphics,
-# EDL, AAF…) keep their spelling. This catalog covers every menu, including the native macOS
-# app menu; anything else is shown in English.
+# EDL, AAF…) keep their spelling. The catalog covers the whole interface: first every menu,
+# including the native macOS app menu, then the rest of the Spanish catalog (panels, dialogs,
+# effects and their parameters, presets, settings, status messages). Strings added later show in
+# English until they are translated.
#
# Terms: track = Spur, bin = Ablage, marker = Marker, playhead = Abspielposition, In/Out = In-/Out-
# Punkt, transition = Übergang, frame hold = Standbild, panel = Bedienfeld, workspace =
# Arbeitsbereich, label (colour) = Farbmarkierung, preferences (also the native macOS Settings
-# menu) = Voreinstellungen. "Timeline" is not translated.
+# menu) = Voreinstellungen. "Timeline" is not translated. Further: frame = Frame, keyframe =
+# Keyframe, preset = Vorgabe, footage = Material, render = rendern, application = Anwendung;
+# ripple, roll, slip and slide edits keep their names (Ripple-Trimmen, Rollen-Werkzeug…); in
+# Lumetri highlights = Lichter, shadows = Tiefen, midtones = Mitteltöne. Keys: Shift = Umschalt,
+# Option = Wahl, Ctrl = Strg.
AAF… AAF…
About FilmCraft Über FilmCraft
@@ -391,3 +397,3219 @@
Zoom to Sequence Auf Sequenz zoomen
Project Notes Projektnotizen
+
+# Beyond the menus, in the order of the Spanish catalog.
+
+ Refresh Changed Media Geänderte Medien aktualisieren
+ Medium Mittel
+ Recent Zuletzt verwendet
+ Home Start
+ Import Importieren
+ {name} - Edited {name} – bearbeitet
+ Full screen Vollbild
+ Volume Lautstärke
+ Master volume: use the Audio Track Mixer Gesamtlautstärke: über das Audiospur-Mischpult
+ Search Suchen
+ Quick Export Schnellexport
+ Join the ArtCraft Discord (discord.gg/artcraft) Dem ArtCraft-Discord beitreten (discord.gg/artcraft)
+ Cancel Abbrechen
+ OK OK
+ Interpret Footage Material interpretieren
+ Color Management · {n} item Farbmanagement · {n} Element
+ Color Management · {n} items Farbmanagement · {n} Elemente
+ Media colour space (from file metadata): {detected} Farbraum des Mediums (aus den Datei-Metadaten): {detected}
+ Override media colour space: Farbraum des Mediums überschreiben:
+ Use file metadata Datei-Metadaten verwenden
+ Sequence Color Management Farbmanagement der Sequenz
+ Working Color Space Arbeitsfarbraum
+ Wide gamut color (composite in BT.2020) Farben mit großem Farbumfang (in BT.2020 zusammensetzen)
+ Auto tone map media (HDR and log into SDR) Automatisches Tone-Mapping für Medien (HDR und Log nach SDR)
+ Audio Gain Audioverstärkung
+ Set Gain to: Verstärkung festlegen auf:
+ Adjust Gain by: Verstärkung anpassen um:
+ Normalize Max Peak to: Maximale Spitze normalisieren auf:
+ Normalize All Peaks to: Alle Spitzen normalisieren auf:
+ Peak Amplitude: {peak} Spitzenamplitude: {peak}
+ Standard Standard
+ Adaptive Adaptiv
+ Mono Mono
+ Stereo Stereo
+ Add Tracks Spuren hinzufügen
+ Amount Anzahl
+ Placement Platzierung
+ Track type Spurtyp
+ Add video tracks Videospuren hinzufügen
+ Add audio tracks Audiospuren hinzufügen
+ Add audio submix tracks Audio-Submix-Spuren hinzufügen
+ After {name} Nach {name}
+ Before First Track Vor der ersten Spur
+ Delete Tracks Spuren löschen
+ Video Tracks Videospuren
+ Audio Tracks Audiospuren
+ Delete Video Tracks Videospuren löschen
+ Delete Audio Tracks Audiospuren löschen
+ All Empty Tracks Alle leeren Spuren
+ Caption Tracks Untertitelspuren
+ Delete Caption Tracks Untertitelspuren löschen
+ Delete Caption Track Untertitelspur löschen
+ Delete Empty Caption Tracks Leere Untertitelspuren löschen
+ Version {version} Version {version}
+ A clean-room, pure-Rust non-linear video editor. Part of the ArtCraft family. Ein nichtlinearer Videoeditor in reinem Rust, im Clean-Room-Verfahren entwickelt. Teil der ArtCraft-Familie.
+ Join the ArtCraft Discord Dem ArtCraft-Discord beitreten
+ Source code on GitHub Quellcode auf GitHub
+ Report an issue Problem melden
+ MIT OR Apache-2.0. Fonts: Inter, Noto Serif and JetBrains Mono (SIL OFL 1.1). MIT OR Apache-2.0. Schriften: Inter, Noto Serif und JetBrains Mono (SIL OFL 1.1).
+ just now gerade eben
+ {n} s ago vor {n} s
+ {n} min ago vor {n} Min.
+ {n} h ago vor {n} Std.
+ All Events Alle Ereignisse
+ Warnings and Errors Warnungen und Fehler
+ Errors Only Nur Fehler
+ Clear All Alle löschen
+ No events. Keine Ereignisse.
+ Show finished jobs Abgeschlossene Aufträge anzeigen
+ Cancelled Abgebrochen
+ Failed: {e} Fehlgeschlagen: {e}
+ Done Fertig
+ No background jobs. Keine Hintergrundaufträge.
+ Recover Unsaved Changes Nicht gespeicherte Änderungen wiederherstellen
+ Untitled Unbenannt
+ FilmCraft was closed while “{name}” had unsaved changes. FilmCraft wurde geschlossen, während „{name}“ nicht gespeicherte Änderungen hatte.
+ FilmCraft quit unexpectedly while “{name}” had unsaved changes. FilmCraft wurde unerwartet beendet, während „{name}“ nicht gespeicherte Änderungen hatte.
+ Recover unsaved changes from {when}? Nicht gespeicherte Änderungen von {when} wiederherstellen?
+ The project had not been saved yet. Das Projekt war noch nicht gespeichert worden.
+ {n} sessions have unsaved changes: {n} Sitzungen haben nicht gespeicherte Änderungen:
+ Discard Verwerfen
+ Recover Wiederherstellen
+ Not Now Nicht jetzt
+ Are you sure you want to discard your changes to '{file}'? Möchtest du deine Änderungen an „{file}“ wirklich verwerfen?
+ Yes Ja
+ No Nein
+ Add media to your project. Drop files anywhere in the window, or choose a source below. Füge deinem Projekt Medien hinzu. Zieh Dateien irgendwo ins Fenster oder wähle unten eine Quelle.
+ Browse files… Dateien durchsuchen…
+ Movies, audio and stills from disk Filme, Audio und Standbilder von der Festplatte
+ Demo footage Demomaterial
+ Six procedural 1080p clips with sound Sechs prozedural erzeugte 1080p-Clips mit Ton
+ Demo project Demoprojekt
+ A cut sequence with transitions, effects and music Eine geschnittene Sequenz mit Übergängen, Effekten und Musik
+ Bars and Tone Farbbalken und Ton
+ SMPTE HD bars with 1 kHz reference tone SMPTE-HD-Farbbalken mit 1-kHz-Referenzton
+ Community Community
+ Join us on Discord Komm zu uns auf Discord
+ OMF Export Settings OMF-Exporteinstellungen
+ AAF Export Settings AAF-Exporteinstellungen
+ OMF Title: OMF-Titel:
+ Mixdown video Video abmischen
+ Audio: Audio:
+ Encapsulate Kapseln
+ Separate Audio Separates Audio
+ Embed Einbetten
+ Separate Files Separate Dateien
+ Link to Media Mit Medien verknüpfen
+ Audio File Format: Audiodateiformat:
+ Sample Rate: Abtastrate:
+ Bits per Sample: Bits pro Sample:
+ Rendering: Rendern:
+ Trim audio files Audiodateien trimmen
+ Handle Frames: Zugabe-Frames:
+ Render audio clip effects Audioclip-Effekte rendern
+ Breakout to mono In Mono aufteilen
+ Exported {path} Exportiert: {path}
+ Select a clip to view its metadata. Wähle einen Clip aus, um seine Metadaten anzuzeigen.
+ Clip: {name} Clip: {name}
+ Open Öffnen
+ (no sequence) (keine Sequenz)
+ Show or hide {color} markers {color}-Marker ein- oder ausblenden
+ Marker Marker
+ {tc} Chapter {tc} Kapitel
+ No markers. Press M to add one. Keine Marker. Drück M, um einen hinzuzufügen.
+ All markers are hidden by the colour filter. Der Farbfilter blendet alle Marker aus.
+ Type: Typ:
+ Video: Video:
+ Codec: Codec:
+ Duration: Dauer:
+ Settings: Einstellungen:
+ Playhead: Abspielposition:
+ Video {n}: Video {n}:
+ Audio {n}: Audio {n}:
+ UI: Oberfläche:
+ {fps} fps · {n} frames queued {fps} fps · {n} Frames in der Warteschlange
+ {panel} — coming in a later milestone {panel} – kommt in einem späteren Meilenstein
+ Close Panel Bedienfeld schließen
+ Close Other Timeline Panels Andere Timeline-Bedienfelder schließen
+ Close All Alle schließen
+ Maximize Frame Rahmen maximieren
+ Restore Frame Rahmen wiederherstellen
+ Restore Workspace Arbeitsbereich wiederherstellen
+ Reveal Sequence in Project Sequenz im Projekt anzeigen
+ Video Thumbnails Video-Miniaturen
+ Audio Waveforms Audio-Wellenformen
+ Delete Preset Vorgabe löschen
+ Export Preset… Vorgabe exportieren…
+ Import Presets… Vorgaben importieren…
+ Effect presets Effektvorgaben
+ Save Preset Vorgabe speichern
+ Name: Name:
+ Type Typ
+ Scale Skalieren
+ Anchor to In Point Am In-Punkt verankern
+ Anchor to Out Point Am Out-Punkt verankern
+ Without keyframes Ohne Keyframes
+ Description: Beschreibung:
+ Saved preset “{name}” Vorgabe „{name}“ gespeichert
+ Current duration {seconds} s Aktuelle Dauer {seconds} s
+ Remix Properties Remix-Eigenschaften
+ Target Duration: Zieldauer:
+ Segments: Segmente:
+ Fewer · More Weniger · Mehr
+ Variations: Variationen:
+ Remixed to {seconds} s Auf {seconds} s geremixt
+ {mode} · no clip {mode} · kein Clip
+ {mode} · no sequence {mode} · keine Sequenz
+ Remove Row Zeile entfernen
+ Add a timecode row Timecode-Zeile hinzufügen
+ Panner Panner
+ Mute Stumm
+ Send {n} Level Pegel Send {n}
+ Show Keyframes Keyframes anzeigen
+ Clip Keyframes Clip-Keyframes
+ Track Keyframes Spur-Keyframes
+ Delete Löschen
+ Untitled Workspace Unbenannter Arbeitsbereich
+ New Workspace Neuer Arbeitsbereich
+ Edit Workspaces Arbeitsbereiche bearbeiten
+ Rename Umbenennen
+ Restore Original Original wiederherstellen
+ Search effects Effekte suchen
+ Apply to Selected Clips Auf ausgewählte Clips anwenden
+ Metadata Display Metadatenanzeige
+ Save As New View Preset Als neue Ansichtsvorgabe speichern
+ Manage Saved View Presets Gespeicherte Ansichtsvorgaben verwalten
+ Freeform View Options Optionen für die freie Ansicht
+ Save Arrangement Anordnung speichern
+ Saves the view, columns, sort, thumbnail and font size. Speichert Ansicht, Spalten, Sortierung, Miniatur- und Schriftgröße.
+ Grid spacing: Rasterabstand:
+ Default clip size: Standard-Clipgröße:
+ Snap to grid Am Raster ausrichten
+ Show clip names Clipnamen anzeigen
+ Show durations Dauer anzeigen
+ Show: Anzeigen:
+ Search fields Felder durchsuchen
+ Project Metadata Projektmetadaten
+ Add Property… Eigenschaft hinzufügen…
+ Column order Spaltenreihenfolge
+ {n}. (empty) {n}. (leer)
+ Restore Wiederherstellen
+ Overwrite with Current View Mit aktueller Ansicht überschreiben
+ Graphics text search arrives with M10.1–M10.2 Die Textsuche in Grafiken kommt mit M10.1–M10.2
+ Open a sequence to work with captions Öffne eine Sequenz, um mit Untertiteln zu arbeiten
+ Add captions Untertitel hinzufügen
+ Create a caption track or import a caption file. Erstelle eine Untertitelspur oder importiere eine Untertiteldatei.
+ Create new caption track Neue Untertitelspur erstellen
+ Import captions file… Untertiteldatei importieren…
+ New {format} track Neue {format}-Spur
+ Add caption at playhead Untertitel an Abspielposition hinzufügen
+ Split caption at playhead Untertitel an Abspielposition teilen
+ Merge selected captions Ausgewählte Untertitel zusammenführen
+ Delete selected captions Ausgewählte Untertitel löschen
+ No captions on this track. Press + to add one at the playhead. Keine Untertitel auf dieser Spur. Drück +, um einen an der Abspielposition hinzuzufügen.
+ No matching captions. Keine passenden Untertitel.
+ Open a sequence to see its transcript Öffne eine Sequenz, um ihr Transkript zu sehen
+ Transcribe sequence Sequenz transkribieren
+ Speech-to-text turns the dialogue into editable text. Spracherkennung macht aus dem Dialog bearbeitbaren Text.
+ This build has no speech-to-text; import a transcript with transcript.set. Dieser Build hat keine Spracherkennung; importiere ein Transkript mit transcript.set.
+ Transcribe Transkribieren
+ Extract selected text Ausgewählten Text extrahieren
+ Lift selected text Ausgewählten Text herausheben
+ Remove filler words Füllwörter entfernen
+ Create captions Untertitel erstellen
+ Speaker Sprecher
+ Box Kasten
+ Align Ausrichten
+ Align left Linksbündig
+ Align center Zentriert
+ Align right Rechtsbündig
+ Position Position
+ Position: top Position: oben
+ Position: middle Position: Mitte
+ Position: bottom Position: unten
+ (gap) (Lücke)
+ Out: {name} Out: {name}
+ In: {name} In: {name}
+ Play Around Edit (Space loops, Shift+K once) Um Schnitt herum abspielen (Leertaste in Schleife, Umschalt+K einmal)
+ Trim Backward Many Weit rückwärts trimmen
+ Trim Backward Rückwärts trimmen
+ Apply Default Transitions Standardübergänge anwenden
+ Apply Default Transitions to Selection (Shift+D) Standardübergänge auf Auswahl anwenden (Umschalt+D)
+ Trim Forward Vorwärts trimmen
+ Trim Forward Many Weit vorwärts trimmen
+ Exit Trim Mode Trimmmodus beenden
+ Voice-over record (right-click: Voice-Over Record Settings…) Voice-over aufnehmen (Rechtsklick: Voice-over-Aufnahmeeinstellungen…)
+ Voice-Over Record Settings… Voice-over-Aufnahmeeinstellungen…
+ Recording voice-over… Voice-over wird aufgenommen…
+ Voice-over recorded: {p} Voice-over aufgenommen: {p}
+ Voice-over recording stopped (nothing recorded) Voice-over-Aufnahme gestoppt (nichts aufgenommen)
+ Post-roll Nachlauf
+ ● Recording ● Aufnahme
+ Voice-Over Record Settings Voice-over-Aufnahmeeinstellungen
+ Source: Quelle:
+ Default Input Standardeingang
+ Input: Eingang:
+ Channel {n} Kanal {n}
+ Countdown Sound Cues Countdown-Signaltöne
+ Pre-roll: Vorlauf:
+ seconds Sekunden
+ Post-roll: Nachlauf:
+ Playback starts the pre-roll before the playhead (or the In point); with In/Out marked, recording punches in and out there. Die Wiedergabe beginnt mit dem Vorlauf vor der Abspielposition (oder dem In-Punkt); sind In und Out gesetzt, startet und endet die Aufnahme dort (Punch-in/-out).
+ Effect Effekt
+ Clip Fx Editor Clip-Effekteditor
+ Track Fx Editor Spur-Effekteditor
+ Master Gain Gesamtverstärkung
+ Reset Zurücksetzen
+ Band {n} Band {n}
+ Solo Solo
+ Bypass Bypass
+ Thr Schw.
+ Ratio Ratio
+ Att Att.
+ Rel Rel.
+ Gain Verstärkung
+ Output Gain Ausgangsverstärkung
+ Limiter Limiter
+ Link Channels Kanäle verknüpfen
+ Limiter Threshold Limiter-Schwellenwert
+ Limiter Release Limiter-Release
+ Auto Gate Auto-Gate
+ Threshold Schwellenwert
+ Attack Attack
+ Release Release
+ Hold Hold
+ Compressor Kompressor
+ Auto Makeup Automatischer Make-up-Gain
+ Makeup Make-up-Gain
+ Expander Expander
+ Soft Clip Soft Clip
+ (no sequences) (keine Sequenzen)
+ (no clips) (keine Clips)
+ Show Transport Controls Transportsteuerung anzeigen
+ Loop Schleife
+ Multi-Camera Audio Follows Video Mehrkamera-Audio folgt Video
+ Multi-Camera Record Mehrkamera-Aufnahme
+ Multi-Camera Selection Top Down Mehrkamera-Auswahl von oben nach unten
+ Show Multi-Camera Preview Monitor Mehrkamera-Vorschaumonitor anzeigen
+ Auto-Adjust Multi-Camera Playback Quality Mehrkamera-Wiedergabequalität automatisch anpassen
+ Transmit Multi-Camera View Mehrkameraansicht übertragen
+ Multi-Camera Layout Mehrkamera-Layout
+ Automatic Automatisch
+ Edit Cameras… Kameras bearbeiten…
+ Add Marker (M) Marker hinzufügen (M)
+ Mark In (I) In-Punkt setzen (I)
+ Mark Out (O) Out-Punkt setzen (O)
+ Go to In (Shift+I) Zum In-Punkt gehen (Umschalt+I)
+ Step Back 1 Frame (Left) 1 Frame zurück (Links)
+ Play-Stop Toggle (Space) Wiedergabe/Stopp (Leertaste)
+ Step Forward 1 Frame (Right) 1 Frame vor (Rechts)
+ Go to Out (Shift+O) Zum Out-Punkt gehen (Umschalt+O)
+ Insert (,) Einfügen (,)
+ Overwrite (.) Überschreiben (.)
+ Export Frame (Shift+E) Frame exportieren (Umschalt+E)
+ Lift (;) Herausheben (;)
+ Extract (') Extrahieren (')
+ Export Frame: use Export mode (M6) Frame exportieren: verwende den Exportmodus (M6)
+ Button Editor Schaltflächen-Editor
+ More transport controls Weitere Transportsteuerelemente
+ Multi-Camera Record on Mehrkamera-Aufnahme an
+ Multi-Camera Record off Mehrkamera-Aufnahme aus
+ {first} - Merged {first} – zusammengeführt
+ {first} Multicam {first} Mehrkamera
+ In Points In-Punkte
+ Out Points Out-Punkte
+ Clip Marker Clipmarker
+ Merge Clips Clips zusammenführen
+ Create Multi-Camera Source Sequence Mehrkamera-Quellsequenz erstellen
+ Synchronize Clips Clips synchronisieren
+ Clip Name: Clipname:
+ Sequence Name: Sequenzname:
+ {n} clip(s): {names} {n} Clip(s): {names}
+ {n} clip(s) selected; the clip on the reference track stays put. {n} Clip(s) ausgewählt; der Clip auf der Referenzspur bleibt, wo er ist.
+ Synchronize Point Synchronisationspunkt
+ Ignore Hours Stunden ignorieren
+ first marker erster Marker
+ Offset Audio by: Audio versetzen um:
+ Offset: Versatz:
+ frames Frames
+ Reference track: Referenzspur:
+ lowest (V1…) unterste (V1…)
+ Remove Audio from AV Clip Audio aus AV-Clip entfernen
+ Camera 1 Kamera 1
+ All Cameras Alle Kameras
+ Switch Audio Audio umschalten
+ Camera Names Kameranamen
+ Clip Names Clipnamen
+ Enumerate Cameras Kameras nummerieren
+ Camera Angle Metadata Kamerawinkel-Metadaten
+ Move source clips to Processed Clips bin Quellclips in die Ablage „Verarbeitete Clips“ verschieben
+ Synchronized {n} clip group(s) {n} Clipgruppe(n) synchronisiert
+ Merged clip created Zusammengeführter Clip erstellt
+ Multi-camera source sequence with {n} camera(s) Mehrkamera-Quellsequenz mit {n} Kamera(s)
+ No multi-camera clip at the playhead Kein Mehrkamera-Clip an der Abspielposition
+ Camera {n} — {name} Kamera {n} – {name}
+ Page {page} of {pages} Seite {page} von {pages}
+ Previous page Vorherige Seite
+ Next page Nächste Seite
+ Multi-Camera Record On/Off (0) Mehrkamera-Aufnahme ein/aus (0)
+ Record Aufnehmen
+ Edit Cameras Kameras bearbeiten
+ Cameras shown in the Multi-Camera view (uncheck to hide). In der Mehrkameraansicht gezeigte Kameras (Häkchen entfernen zum Ausblenden).
+ Recorded {n} multi-camera cut(s) {n} Mehrkamera-Schnitt(e) aufgenommen
+ Clamp Signal Signal begrenzen
+ Presets Vorgaben
+ Parade ({kind}) Parade ({kind})
+ Waveform ({kind}) Wellenform ({kind})
+ Parade Type Paradetyp
+ Waveform Type Wellenformtyp
+ Vectorscope Targets Vektorskop-Zielmarken
+ Colour Space Farbraum
+ Brightness Helligkeit
+ Signal Scale Signalskala
+ Histogram Histogramm
+ Paste Attributes Attribute einfügen
+ Remove Attributes Attribute entfernen
+ New Offline File Neue Offline-Datei
+ Nested Sequence Name Name der verschachtelten Sequenz
+ Make Subclip Subclip erstellen
+ Edit Subclip Subclip bearbeiten
+ Modify Clip: Audio Channels Clip ändern: Audiokanäle
+ Modify Clip: Timecode Clip ändern: Timecode
+ Frame Hold Options Standbildoptionen
+ Field Options Halbbildoptionen
+ Save Project Projekt speichern
+ Motion Bewegung
+ Opacity Deckkraft
+ Time Remapping Zeitneuzuordnung
+ Channel Volume Kanallautstärke
+ In Point In-Punkt
+ Out Point Out-Punkt
+ Playhead Abspielposition
+ Source Timecode Quell-Timecode
+ Sequence Time Sequenzzeit
+ Video Attributes Videoattribute
+ Audio Attributes Audioattribute
+ No effects Keine Effekte
+ Scale Attribute Times Attributzeiten skalieren
+ File Name: Dateiname:
+ Tape Name: Bandname:
+ Contains: Enthält:
+ Video Video
+ Width: Breite:
+ Height: Höhe:
+ Frame Rate: Framerate:
+ Media Start: Medienstart:
+ Subclip: {name} Subclip: {name}
+ Start: Start:
+ End: Ende:
+ Restrict Trims To Subclip Boundaries Trimmen auf Subclip-Grenzen beschränken
+ Convert to Master Clip In Master-Clip umwandeln
+ Clip Channel Format: Kanalformat des Clips:
+ Number of Audio Clips: Anzahl der Audioclips:
+ Media Source Channels Kanäle der Medienquelle
+ Ch. {n} K. {n}
+ Clip {n} Clip {n}
+ Source channels the selected audio clips play: Quellkanäle, die die ausgewählten Audioclips wiedergeben:
+ Set Timecode: Timecode festlegen:
+ Use the file's timecode Timecode der Datei verwenden
+ Hold On Halten bei
+ Timecode: Timecode:
+ Hold Filters Filter halten
+ Reverse Field Dominance Halbbilddominanz umkehren
+ Processing Options Verarbeitungsoptionen
+ None Keine
+ Always Deinterlace Immer Deinterlacing anwenden
+ Flicker Removal Flimmerentfernung
+ Save changes to “{project_name}” before closing? Änderungen an „{project_name}“ vor dem Schließen speichern?
+ Don't Save Nicht speichern
+ All media is online. Alle Medien sind online.
+ {name} (copy) {name} (Kopie)
+ Offline Offline
+ Missing Fehlt
+ Link Media Medien verknüpfen
+ {n} clip(s) can't find their media. Locate them, search a folder, or leave them offline. {n} Clip(s) finden ihre Medien nicht. Such sie, durchsuche einen Ordner oder lass sie offline.
+ Clip Name Clipname
+ File Name Dateiname
+ File Path Dateipfad
+ Status Status
+ Match file properties: Übereinstimmende Dateieigenschaften:
+ File Extension Dateierweiterung
+ Clip ID (fingerprint) Clip-ID (Fingerabdruck)
+ Duration Dauer
+ Media Start Medienstart
+ Frame Size / Rate Bildgröße/-rate
+ Align Timecode Timecode ausrichten
+ Relink others automatically Andere automatisch neu verknüpfen
+ Search in: Suchen in:
+ Browse… Durchsuchen…
+ A file dialog is already open Ein Dateidialog ist bereits geöffnet
+ Exact name matches only Nur exakte Namenstreffer
+ No candidates yet — Search a folder or Locate the file. Noch keine Kandidaten – durchsuche einen Ordner oder such die Datei.
+ ✔ same file ✔ dieselbe Datei
+ ✔ matches ✔ passt
+ ✖ different file ✖ andere Datei
+ Preview Vorschau
+ Offline All Alle offline
+ Locate… Datei suchen…
+ Linked {n} clip(s) {n} Clip(s) verknüpft
+ Nothing found with that name. Unter diesem Namen wurde nichts gefunden.
+ Make Offline Offline setzen
+ Make {n} selected clip(s) offline. Their clips show the offline slate until you link them again. {n} ausgewählte(n) Clip(s) offline setzen. Die Clips zeigen die Offline-Tafel, bis du sie wieder verknüpfst.
+ Media files remain on disk Mediendateien bleiben auf der Festplatte
+ Media files are deleted Mediendateien werden gelöscht
+ Create Proxies Proxys erstellen
+ {n} clip(s) selected. {n} Clip(s) ausgewählt.
+ Format and size Format und Größe
+ Destination Ziel
+ Next to the original media, in a Proxies folder Neben den Originalmedien, in einem Ordner „Proxies“
+ Proxies are made in the background and attached when done. Export always uses full-resolution media. Proxys werden im Hintergrund erstellt und nach Abschluss angehängt. Der Export verwendet immer Medien in voller Auflösung.
+ Creating {n} proxy file(s)… {n} Proxy-Datei(en) werden erstellt…
+ Project Manager Projektmanager
+ Sequences Sequenzen
+ Resulting Project Resultierendes Projekt
+ Collect Files and Copy to New Location Dateien sammeln und an neuen Speicherort kopieren
+ Consolidate and Transcode Zusammenfassen und transkodieren
+ Options Optionen
+ Exclude Unused Clips Nicht verwendete Clips ausschließen
+ Include Handles: Zugaben einschließen:
+ Include Proxies Proxys einschließen
+ Include Preview Files Vorschaudateien einschließen
+ Destination Path Zielpfad
+ Disk space: original {original} · resulting {result} ({n} files) Speicherplatz: Original {original} · Ergebnis {result} ({n} Dateien)
+ Disk space: — Speicherplatz: –
+ Calculate Berechnen
+ Project Manager: writing {path} Projektmanager: {path} wird geschrieben
+ Timeline: (no sequences) Timeline: (keine Sequenzen)
+ Browse Durchsuchen
+ Select audio clips, then click a preset to apply it. Wähle Audioclips aus und klick dann auf eine Vorgabe, um sie anzuwenden.
+ {name} (user) {name} (Benutzer)
+ Select audio clips to edit them here Wähle Audioclips aus, um sie hier zu bearbeiten
+ Multiple Clips Selected Mehrere Clips ausgewählt
+ The selected clips have different audio types. Assign one type to edit them together. Die ausgewählten Clips haben unterschiedliche Audiotypen. Weise einen Typ zu, um sie gemeinsam zu bearbeiten.
+ Assign an audio type to the selection: Weise der Auswahl einen Audiotyp zu:
+ Clear Audio Type Audiotyp entfernen
+ Preset: Vorgabe:
+ (Custom) (Benutzerdefiniert)
+ Preset name Vorgabenname
+ Reduce Noise Rauschen reduzieren
+ Reduce Rumble Rumpeln reduzieren
+ DeHum Brummen entfernen
+ DeEss De-Esser
+ Reduce Reverb Hall reduzieren
+ Dynamics Dynamik
+ EQ EQ
+ Enhance Speech Sprache verbessern
+ Low Tone Tiefen
+ High Tone Höhen
+ Mix Mischung
+ Reverb Hall
+ Stereo Width Stereobreite
+ Remixing music to a target duration is not available yet. Trim the clip and add a crossfade instead. Musik auf eine Zieldauer zu remixen ist noch nicht verfügbar. Trimme stattdessen den Clip und füge eine Überblendung hinzu.
+ Pan Panorama
+ Auto-Match Automatisch angleichen
+ Not matched yet Noch nicht angeglichen
+ Matches each of the {n} clips on its own. Gleicht jeden der {n} Clips einzeln an.
+ Duck against: Absenken gegenüber:
+ Untagged Ohne Typ
+ Sensitivity Empfindlichkeit
+ Reduce By Absenken um
+ Fades Blenden
+ Generate Keyframes Keyframes erzeugen
+ Clip Volume Cliplautstärke
+ (no clip selected) (kein Clip ausgewählt)
+ Master · {name} Master · {name}
+ Add Lumetri Color to clip Lumetri-Farbe zum Clip hinzufügen
+ Input LUT Eingabe-LUT
+ Temperature Temperatur
+ Tint Tönung
+ Saturation Sättigung
+ Exposure Belichtung
+ Contrast Kontrast
+ Highlights Lichter
+ Shadows Tiefen
+ Whites Weiß
+ Blacks Schwarz
+ HDR HDR
+ HDR White HDR-Weiß
+ HDR Specular HDR-Spitzlichter
+ Look Look
+ Look LUT Look-LUT
+ Intensity Intensität
+ Adjustments Anpassungen
+ Faded Film Verblasster Film
+ Sharpen Scharfzeichnen
+ Vibrance Dynamik
+ RGB Curves RGB-Kurven
+ HDR Range HDR-Bereich
+ Hue Saturation Curves Farbton-Sättigungs-Kurven
+ Hue vs Sat Farbton/Sättigung
+ Hue vs Hue Farbton/Farbton
+ Hue vs Luma Farbton/Luminanz
+ Luma vs Sat Luminanz/Sättigung
+ Sat vs Sat Sättigung/Sättigung
+ Midtones Mitteltöne
+ Key Key
+ Hue Farbton
+ Hue Range Farbtonbereich
+ Saturation Min Minimale Sättigung
+ Luma Min Minimale Luminanz
+ Luma Max Maximale Luminanz
+ Soften Weichzeichnen
+ Show Mask Maske anzeigen
+ Off Aus
+ Color/Gray Farbe/Grau
+ Color/Black Farbe/Schwarz
+ White/Black Weiß/Schwarz
+ Refine Verfeinern
+ Denoise Entrauschen
+ Blur Weichzeichner
+ Correction Korrektur
+ Hue Shift Farbtonverschiebung
+ Midpoint Mittelpunkt
+ Roundness Rundheit
+ Feather Weiche Kante
+ LUT LUT
+ Color Match Farbabgleich
+ Reference Referenz
+ Face Detection (protect skin tones) Gesichtserkennung (Hauttöne schützen)
+ Apply Match Abgleich anwenden
+ Create ellipse mask Ellipsenmaske erstellen
+ Create 4-point polygon mask 4-Punkt-Polygonmaske erstellen
+ Free draw bezier Freihand-Bézier
+ Click in the Program monitor to place mask points (drag for curves); click the first point or press Enter to close Klick in den Programmmonitor, um Maskenpunkte zu setzen (ziehen für Kurven); klick auf den ersten Punkt oder drück die Eingabetaste, um sie zu schließen
+ Delete Mask Maske löschen
+ Inverted Umgekehrt
+ Drag: move · Alt-click: smooth/corner · Cmd-click: delete Ziehen: verschieben · Alt+Klick: glatt/Ecke · Cmd+Klick: löschen
+ Track selected mask backward Ausgewählte Maske rückwärts verfolgen
+ Track selected mask backward 1 frame Ausgewählte Maske 1 Frame rückwärts verfolgen
+ Track selected mask forward 1 frame Ausgewählte Maske 1 Frame vorwärts verfolgen
+ Track selected mask forward Ausgewählte Maske vorwärts verfolgen
+ Stop tracking Verfolgung stoppen
+ Tracking method: {method} Verfolgungsmethode: {method}
+ Composite Zusammengesetzt
+ Comparison Vergleich
+ Video and Waveform Video und Wellenform
+ System Default Systemstandard
+ Default location Standardspeicherort
+ Font family Schriftfamilie
+ Label Colors Markierungsfarben
+ Decoded frames held for the monitors and thumbnails: {used} of {budget}. Für Monitore und Miniaturen vorgehaltene dekodierte Frames: {used} von {budget}.
+ FilmCraft keeps the rest of the RAM free for other applications. FilmCraft lässt den restlichen Arbeitsspeicher für andere Programme frei.
+ not available in this session in dieser Sitzung nicht verfügbar
+ Currently: {loc} — {files} file(s), {size} Aktuell: {loc} – {files} Datei(en), {size}
+ ({ch} output channels) ({ch} Ausgangskanäle)
+ Programme left → device output {l}, right → device output {r}{dev}. Outputs beyond the device's channels fall back to 1 and 2. Programm links → Geräteausgang {l}, rechts → Geräteausgang {r}{dev}. Ausgänge über die Kanalzahl des Geräts hinaus fallen auf 1 und 2 zurück.
+ Auto-saves go to: {dir} Automatische Speicherungen landen in: {dir}
+ Recovery copy: {dir} Wiederherstellungskopie: {dir}
+ Last auto-save {a} · last recovery copy {j} Letzte automatische Speicherung {a} · letzte Wiederherstellungskopie {j}
+ Last auto-save {a} Letzte automatische Speicherung {a}
+ Last recovery copy {j} Letzte Wiederherstellungskopie {j}
+ Remove Media Cache Files Mediencache-Dateien entfernen
+ Deleted {n} file(s), {size}. {n} Datei(en) gelöscht, {size}.
+ Reset… Zurücksetzen…
+ Source · {name} Quelle · {name}
+ Reset Effect Effekt zurücksetzen
+ Reset Parameter Parameter zurücksetzen
+ Save Preset… Vorgabe speichern…
+ Custom Setup Benutzerdefinierte Einrichtung
+ Edit… Bearbeiten…
+ Show graphs Diagramme anzeigen
+ Toggle animation Animation ein/aus
+ Eyedropper (pick a color from the Program monitor) Pipette (Farbe aus dem Programmmonitor aufnehmen)
+ Eyedropper: no picture to sample Pipette: kein Bild zum Aufnehmen
+ Add/Remove Keyframe Keyframe hinzufügen/entfernen
+ Temporal Interpolation Zeitliche Interpolation
+ Linear Linear
+ Bezier Bézier
+ Auto Bezier Automatische Bézier
+ Continuous Bezier Kontinuierliche Bézier
+ Ease In Ease In
+ Ease Out Ease Out
+ Select a clip to grade Wähle einen Clip zum Graden aus
+ Select a clip to see its properties Wähle einen Clip aus, um seine Eigenschaften zu sehen
+ Anchor point Ankerpunkt
+ Rotation Drehung
+ Level Pegel
+ Speed {n}% Geschwindigkeit {n} %
+ Value Wert
+ Velocity Geschwindigkeit
+ Default Standard
+ Custom ({n} points) Benutzerdefiniert ({n} Punkte)
+ Select a graphic clip, or use the Type tool (T) on the Program monitor Wähle einen Grafikclip aus oder verwende das Textwerkzeug (T) im Programmmonitor
+ Create new graphic Neue Grafik erstellen
+ New Text Layer Neue Textebene
+ New Text Neuer Text
+ New Rectangle Neues Rechteck
+ New Ellipse Neue Ellipse
+ Delete Layer Ebene löschen
+ Select a layer to edit its properties. Wähle eine Ebene aus, um ihre Eigenschaften zu bearbeiten.
+ Align Left Links ausrichten
+ Align Center Horizontally Horizontal zentrieren
+ Align Right Rechts ausrichten
+ Align Top Oben ausrichten
+ Align Center Vertically Vertikal zentrieren
+ Align Bottom Unten ausrichten
+ Font Schrift
+ Font Style Schriftschnitt
+ Font Size Schriftgröße
+ Alignment Ausrichtung
+ Left Align Text Text linksbündig
+ Center Align Text Text zentrieren
+ Right Align Text Text rechtsbündig
+ Justify Blocksatz
+ Tracking Laufweite
+ Leading Zeilenabstand
+ Baseline Shift Grundlinienversatz
+ Text Box Width Textfeldbreite
+ Style Stil
+ Faux Bold Faux-Fett
+ Faux Italic Faux-Kursiv
+ All Caps Großbuchstaben
+ Small Caps Kapitälchen
+ Underline Unterstrichen
+ OpenType OpenType
+ Kerning Unterschneidung
+ Ligatures Ligaturen
+ Shape Form
+ Size Größe
+ Corner Radius Eckenradius
+ Polygon Sides Polygonseiten
+ Fill Füllung
+ Stroke Kontur
+ Stroke 2 Kontur 2
+ Background Hintergrund
+ Opacity Deckkraft
+ Size Größe
+ Corner Radius Eckenradius
+ Shadow Schatten
+ Angle Winkel
+ Distance Abstand
+ Blur Weichzeichnung
+ Search templates Vorlagen suchen
+ All Categories Alle Kategorien
+ Install… Installieren…
+ Install Motion Graphics Template (.fcgt) Motion-Graphics-Vorlage installieren (.fcgt)
+ No templates match. Keine passenden Vorlagen.
+ {category} · My Template {category} · Meine Vorlage
+ Apply Anwenden
+ Remove Entfernen
+ {n} editable properties {n} bearbeitbare Eigenschaften
+ Template: {name} Vorlage: {name}
+ Intro Duration Dauer des Intros
+ Outro Duration Dauer des Outros
+ Roll Rollen
+ Start Off Screen Außerhalb des Bildes beginnen
+ End Off Screen Außerhalb des Bildes enden
+ Preroll Vorlauf
+ Postroll Nachlauf
+ Video Frame Videobild
+ Pin To Anheften an
+ Pinned Edges Angeheftete Kanten
+ FilmCraft Graphics Template FilmCraft-Grafikvorlage
+ {n} Font {n} Schrift
+ {n} Size {n} Größe
+ {n} Color {n} Farbe
+ {n} Position {n} Position
+ Show {n} {n} anzeigen
+ My Templates Meine Vorlagen
+ Export As Motion Graphics Template Als Motion-Graphics-Vorlage exportieren
+ Category: Kategorie:
+ Editable properties: Bearbeitbare Eigenschaften:
+ Saved as a FilmCraft graphics template (.fcgt) in your templates folder. Wird als FilmCraft-Grafikvorlage (.fcgt) in deinem Vorlagenordner gespeichert.
+ Exported graphics template to {path} Grafikvorlage nach {path} exportiert
+ Replace Fonts in Projects Schriften in Projekten ersetzen
+ Fonts used in the project: Im Projekt verwendete Schriften:
+ {f} (missing) {f} (fehlt)
+ Replace: Ersetzen:
+ Replaced {n} font uses {n} Schriftverwendungen ersetzt
+ Show/Hide Effects and Sends Effekte und Sends ein-/ausblenden
+ Audio Track Mixer menu Menü des Audiospur-Mischpults
+ Show/Hide Tracks… Spuren ein-/ausblenden…
+ Meter Input(s) Only Nur Eingänge messen
+ Show/Hide Tracks Spuren ein-/ausblenden
+ Show All Alle anzeigen
+ Post-Fader Post-Fader
+ Remove Effect Effekt entfernen
+ Fill the slots above first Füll zuerst die Plätze darüber
+ pre pre
+ Pre-Fader Pre-Fader
+ Mute Send Send stummschalten
+ Remove Send Send entfernen
+ New Submix Neuer Submix
+ Pan / balance (drag; double-click: centre) Panorama/Balance (ziehen; Doppelklick: Mitte)
+ Solo safe Solo-sicher
+ Enable track for recording Spur für Aufnahme aktivieren
+ Volume (drag; double-click: 0 dB) Lautstärke (ziehen; Doppelklick: 0 dB)
+ 5.1 panner (drag the puck; double-click: front centre) 5.1-Panner (Punkt ziehen; Doppelklick: vorne Mitte)
+ Center Mitte
+ Go to In Point Zum In-Punkt gehen
+ Go to Out Point Zum Out-Punkt gehen
+ Play In to Out Von In bis Out abspielen
+ Record (voice-over on the record-enabled track) Aufnehmen (Voice-over auf der aufnahmebereiten Spur)
+ Write keyframes Keyframes schreiben
+ Something went wrong while drawing the window. Your project is still open; save it to be safe. Beim Zeichnen des Fensters ist etwas schiefgelaufen. Dein Projekt ist noch geöffnet; speichere es sicherheitshalber.
+ Continue Fortfahren
+ Go Back Zurück
+ Go Forward Vorwärts
+ Up One Level Eine Ebene nach oben
+ File Types Displayed Angezeigte Dateitypen
+ List View Listenansicht
+ Thumbnail View Miniaturansicht
+ Ingest Ingest
+ Open Ingest Settings Ingest-Einstellungen öffnen
+ Import as Image Sequence Als Bildsequenz importieren
+ {sel} of {total} items selected {sel} von {total} Elementen ausgewählt
+ {total} items {total} Elemente
+ Cannot open {dir}: {e} {dir} kann nicht geöffnet werden: {e}
+ Favorites Favoriten
+ Local Drives Lokale Laufwerke
+ Network Netzwerk
+ Recent Directories Zuletzt verwendete Ordner
+ (none) (keine)
+ Remove from Favorites Aus Favoriten entfernen
+ Add to Favorites Zu Favoriten hinzufügen
+ Clear Recent Directories Zuletzt verwendete Ordner leeren
+ Open In Source Monitor Im Quellmonitor öffnen
+ Reveal in Finder Im Dateimanager anzeigen
+ Edit Columns… Spalten bearbeiten…
+ Hover Scrub Hover-Scrubbing
+ New Media Browser Panel Neues Medienbrowser-Bedienfeld
+ Create Folder For Imported Projects Ordner für importierte Projekte erstellen
+ Allow Duplicate Media During Project Import Doppelte Medien beim Projektimport zulassen
+ Refresh Aktualisieren
+ Edit Columns Spalten bearbeiten
+ Guides Hilfslinien
+ (no audio) (kein Audio)
+ Generating waveform… Wellenform wird erzeugt…
+ Reference {tc} Referenz {tc}
+ Set Setzen
+ Set the reference to the playhead Referenz auf die Abspielposition setzen
+ Reference: next frame Referenz: nächster Frame
+ Reference: previous frame Referenz: vorheriger Frame
+ RGBA Channels RGBA-Kanäle
+ Add Guide Hilfslinie hinzufügen
+ Save Guides as Template Hilfslinien als Vorlage speichern
+ Manage Guides Hilfslinien verwalten
+ Orientation: Ausrichtung:
+ Vertical Vertikal
+ Horizontal Horizontal
+ Position: Position:
+ No saved guide templates. Keine gespeicherten Hilfslinienvorlagen.
+ Project: {name} Projekt: {name}
+ Bin: {name} Ablage: {name}
+ Up one level Eine Ebene nach oben
+ Video Usage: {vu} Audio Usage: {au} Videonutzung: {vu} Audionutzung: {au}
+ Icon View Symbolansicht
+ Freeform View Freiformansicht
+ Sort Icons Symbole sortieren
+ Clear (Delete) Löschen (Entf)
+ New Item Neues Element
+ New Bin Neue Ablage
+ Find Suchen
+ Automate to Sequence Automatisch in Sequenz einfügen
+ Select items to clear Wähle die zu löschenden Elemente aus
+ User Order Benutzerdefinierte Reihenfolge
+ Descending Absteigend
+ Refresh Project Projekt aktualisieren
+ Reveal Project in Finder… Projekt im Dateimanager anzeigen…
+ New Bin From Selection Neue Ablage aus Auswahl
+ New Search Bin Neue Suchablage
+ New Project Shortcut Neue Projektverknüpfung
+ List Liste
+ Icon Symbol
+ Freeform Freiform
+ Preview Area Vorschaubereich
+ Thumbnails Miniaturen
+ Thumbnails show effects applied Miniaturen zeigen angewendete Effekte
+ Thumbnail controls for all pointing devices Miniatursteuerung für alle Zeigegeräte
+ Refresh Sort Order Sortierreihenfolge aktualisieren
+ Metadata Display… Metadatenanzeige…
+ Save Current View Preset Aktuelle Ansichtsvorgabe speichern
+ Restore View Preset Ansichtsvorgabe wiederherstellen
+ Project View Preset {n} Projekt-Ansichtsvorgabe {n}
+ Freeform View Options… Optionen für die Freiformansicht…
+ Media missing Medium fehlt
+ Unreadable Nicht lesbar
+ Open in Source Monitor Im Quellmonitor öffnen
+ Open in Timeline In der Timeline öffnen
+ New Sequence From Clip Neue Sequenz aus Clip
+ Set Poster Frame Posterframe festlegen
+ Open in Place An Ort und Stelle öffnen
+ Open in New Tab In neuem Tab öffnen
+ Open in New Window In neuem Fenster öffnen
+ {n} items {n} Elemente
+ Stack Stapeln
+ Unstack Stapel auflösen
+ Clip Size Clipgröße
+ Larger Größer
+ Smaller Kleiner
+ Align to Grid Am Raster ausrichten
+ Reset to Grid Auf Raster zurücksetzen
+ Save Arrangement… Anordnung speichern…
+ Restore Arrangement Anordnung wiederherstellen
+ Delete Arrangement Anordnung löschen
+ Drop media here to create sequence. Zieh Medien hierher, um eine Sequenz zu erstellen.
+ Double-click a sequence in the Project panel to open it here. Doppelklick auf eine Sequenz im Projekt-Bedienfeld öffnet sie hier.
+ Open Demo Project Demoprojekt öffnen
+ Insert and overwrite sequences as nests or individual clips Sequenzen als verschachtelte Sequenz oder einzelne Clips einfügen und überschreiben
+ Snap in Timeline (S) In der Timeline einrasten (S)
+ Caption track options Optionen für Untertitelspuren
+ Timeline Display Settings Anzeigeeinstellungen der Timeline
+ Show Video Thumbnails Video-Miniaturen anzeigen
+ Head Anfang
+ Head and Tail Anfang und Ende
+ Continuous Fortlaufend
+ Show Audio Waveform Audio-Wellenform anzeigen
+ Expand All Tracks Alle Spuren erweitern
+ Minimize All Tracks Alle Spuren minimieren
+ Unrendered: should play back in real time Nicht gerendert: sollte in Echtzeit abspielen
+ Unrendered: render to play back in real time Nicht gerendert: zum Abspielen in Echtzeit rendern
+ Rendered preview Gerenderte Vorschau
+ ✓ Enable ✓ Aktivieren
+ Unlink Verknüpfung aufheben
+ (Default) (Standard)
+ (RGB) Gamma (RGB) Gamma
+ (RGB) Input Black Level (RGB) Eingangsschwarzwert
+ (RGB) Input White Level (RGB) Eingangsweißwert
+ (RGB) Output Black Level (RGB) Ausgangsschwarzwert
+ (RGB) Output White Level (RGB) Ausgangsweißwert
+ + Cmd + Cmd
+ + Opt + Opt
+ 10 Bit Black Point 10-Bit-Schwarzpunkt
+ 10 Bit White Point 10-Bit-Weißpunkt
+ 105mm Prime 105-mm-Festbrennweite
+ 29.97 fps Drop-Frame 29,97 fps Drop-Frame
+ 29.97 fps Non Drop-Frame 29,97 fps Non-Drop-Frame
+ 35mm Prime 35-mm-Festbrennweite
+ 3D Roll 3D-Rollen
+ 3D Rotate 3D-Drehen
+ 3D Spin 3D-Wirbeln
+ 3D Spinback 3D-Rückwirbel
+ 4-Color Gradient 4-Farben-Verlauf
+ 5.1 Media 5.1-Medien
+ 5.1 Mixdown Type 5.1-Abmischtyp
+ 50-300mm Zoom 50–300-mm-Zoom
+ 59.94 fps Drop-Frame 59,94 fps Drop-Frame
+ 59.94 fps Non Drop-Frame 59,94 fps Non-Drop-Frame
+ ASC CDL ASC CDL
+ Accessible color contrast Barrierefreier Farbkontrast
+ Action-Safe Margin Sicherer Aktionsbereich
+ Active Monitor Aktiver Monitor
+ Add Hinzufügen
+ Add tracks automatically when editing source clips onto the Timeline Beim Einfügen von Quellclips in die Timeline automatisch Spuren hinzufügen
+ Place files dropped onto the Timeline directly on the Timeline In die Timeline gezogene Dateien direkt in der Timeline platzieren
+ 1 file 1 Datei
+ {n} files {n} Dateien
+ Additional Scale Zusätzliche Skalierung
+ Additive Dissolve Additive Blende
+ Additive Dissolve (Legacy) Additive Blende (alt)
+ Adjust Anpassen
+ Advanced Erweitert
+ Aggressive Aggressiv
+ Align and Transform Ausrichten und Transformieren
+ All lines Alle Zeilen
+ Allow Selection tool to choose Roll and Ripple trims without modifier key Auswahlwerkzeug darf Rollen- und Ripple-Trimmen ohne Zusatztaste wählen
+ Allow current tool to change trim type of previously selected edit point Aktuelles Werkzeug darf die Trimmart eines bereits ausgewählten Schnittpunkts ändern
+ Allow duplicate media during project import Doppelte Medien beim Projektimport zulassen
+ Alpha Adjust Alpha-Anpassung
+ Alpha Blurriness Alpha-Unschärfe
+ Alpha Channel Alphakanal
+ Alpha Glow Alpha-Glühen
+ Always import embedded CEA-708 closed captions with wide aspect. Eingebettete CEA-708-Untertitel immer im Breitformat importieren.
+ Always override audio tags Audio-Tags immer überschreiben
+ Ambience Umgebung
+ Ambience Intensity Umgebungsintensität
+ Ambience Light Color Farbe des Umgebungslichts
+ Amount of Noise Rauschstärke
+ Amount to Decolor Stärke der Entfärbung
+ Amount to Tint Stärke der Tönung
+ Amplifier Verstärker
+ Amplify Verstärken
+ Amplitude Amplitude
+ Amplitude and Compression Amplitude und Kompression
+ Analog Analog
+ Analog Delay Analoges Delay
+ Analyze all imported media to search for visuals or audio Alle importierten Medien analysieren, um nach Bild- oder Audioinhalten zu suchen
+ Anamorphic Anamorph
+ Anchor Anker
+ Anchor Point Ankerpunkt
+ Angle Winkel
+ Animation Animation
+ Anti-aliasing Quality Kantenglättungsqualität
+ Anti-flicker Filter Flimmerfilter
+ Antialiasing for Best Quality Kantenglättung für beste Qualität
+ Asymmetry Asymmetrie
+ At Startup Beim Start
+ At playback end, return to beginning when restarting playback Am Wiedergabeende beim erneuten Abspielen zum Anfang zurückkehren
+ Attempt to force hardware to document sample rate Versuchen, die Hardware auf die Abtastrate des Dokuments zu zwingen
+ Audio Codec Audiocodec
+ Audio Duration Audiodauer
+ Audio Effects Audioeffekte
+ Audio Hardware Audiohardware
+ Audio In Point Audio-In-Punkt
+ Audio Info Audioinformationen
+ Audio Out Point Audio-Out-Punkt
+ Audio Samples Audio-Samples
+ Audio Time Units Audio-Zeiteinheiten
+ Audio Transition Default Duration Standarddauer für Audioübergänge
+ Audio Transitions Audioübergänge
+ Audio Usage Audionutzung
+ Auto Automatisch
+ Auto Align Automatisch ausrichten
+ Auto Reframe Automatisch neu framen
+ Auto Save Automatisch speichern
+ Auto Save also saves the current project(s) Automatisches Speichern speichert auch die aktuellen Projekte
+ Auto-tag audio types in the timeline Audiotypen in der Timeline automatisch zuweisen
+ Auto-transcribe all imported clips Alle importierten Clips automatisch transkribieren
+ Auto-transcribe only clips in sequences Nur Clips in Sequenzen automatisch transkribieren
+ Automatch Time Zeit für automatischen Abgleich
+ Automatic Click Remover Automatischer Klickentferner
+ Automatically Hide Dependent Clips Abhängige Clips automatisch ausblenden
+ Automatically Save Every Automatisch speichern alle
+ Automatically delete cache files older than Cachedateien automatisch löschen, die älter sind als
+ Automatically delete oldest cache files when cache exceeds Älteste Cachedateien automatisch löschen, wenn der Cache größer wird als
+ Automatically refresh growing files Wachsende Dateien automatisch aktualisieren
+ Automatically resume playback for growing files in Source Monitor Wiedergabe wachsender Dateien im Quellmonitor automatisch fortsetzen
+ Automatically save projects Projekte automatisch speichern
+ Automatically transcribe clips Clips automatisch transkribieren
+ Automation Keyframe Optimization Optimierung von Automations-Keyframes
+ Background Color Hintergrundfarbe
+ Background Corner Radius Eckenradius des Hintergrunds
+ Background Opacity Deckkraft des Hintergrunds
+ Background Size Größe des Hintergrunds
+ Background fill Hintergrundfüllung
+ Balance Balance
+ Balanced Voice Ausgewogene Stimme
+ Band 1 Band 1
+ Band 2 Band 2
+ Band 3 Band 3
+ Band 4 Band 4
+ Band 5 Band 5
+ Band Pass Bandpass
+ Band Slide Bänder schieben
+ Band Stop Bandsperre
+ Bandpass Bandpass
+ Barn Doors Scheunentor
+ Basic Einfach
+ Basic 3D Einfaches 3D
+ Basic Correction Grundlegende Korrektur
+ Bass Bass
+ Behind Dahinter
+ Bessel Bessel
+ Bevel Alpha Alpha abschrägen
+ Bevel join Abgeflachte Ecke
+ Binauralizer - Ambisonics Binauralisierer – Ambisonics
+ Bins Ablagen
+ Black Schwarz
+ Black & White Schwarzweiß
+ Black Input Level Schwarzeingangspegel
+ Black and white Schwarzweiß
+ Black and white with crushed blacks and strong contrast Schwarzweiß mit abgesoffenen Schwarztönen und starkem Kontrast
+ Bleach Bypass Bleach Bypass
+ Bleach-bypass style: desaturated with hard contrast Bleach-Bypass-Stil: entsättigt mit hartem Kontrast
+ Blend Mischen
+ Blend Mode Mischmodus
+ Blend With Original Mit Original mischen
+ Blending Mode Mischmodus
+ Block Dissolve Blockauflösung
+ Block Height Blockhöhe
+ Block Motion Blockbewegung
+ Block Size Blockgröße
+ Block Width Blockbreite
+ Blocks Blöcke
+ Blue Blurriness Unschärfe Blau
+ Blue Curve Kurve Blau
+ Blue Offset Versatz Blau
+ Blue Power Potenz Blau
+ Blue Slope Steigung Blau
+ Blue-Blue Blau-Blau
+ Blue-Const Blau-Konst.
+ Blue-Green Blau-Grün
+ Blue-Red Blau-Rot
+ Blur & Sharpen Weich- und Scharfzeichnen
+ Blur Amount Stärke der Weichzeichnung
+ Blur Angle Winkel der Weichzeichnung
+ Blur Dimensions Weichzeichnungsrichtung
+ Blur Dissolve Weichzeichnende Blende
+ Blur Layer Weichzeichnungsebene
+ Blur Length Länge der Weichzeichnung
+ Blurriness Unschärfe
+ Bokeh Blur Bokeh-Weichzeichner
+ Boost Anhebung
+ Border Rand
+ Border Color Randfarbe
+ Border Width Randbreite
+ Borders Ränder
+ Bottom Center Unten Mitte
+ Bottom Left Unten links
+ Bottom Right Unten rechts
+ Bounce Abprallen
+ Branching Verzweigung
+ Bright Strahlend
+ Bright Air Helle Luft
+ Bright Studio Helles Studio
+ Brightness & Contrast Helligkeit und Kontrast
+ British Stack British Stack
+ Brush Hardness Pinselhärte
+ Brush Opacity Pinseldeckkraft
+ Brush Position Pinselposition
+ Brush Size Pinselgröße
+ Brush Spacing (secs) Pinselabstand (s)
+ Brush Strokes Pinselstriche
+ Bubbles Blasen
+ Bulge Wölbung
+ Bulge Smoother Wölbungsglättung
+ Bump Height Reliefhöhe
+ Burn Alpha Alpha brennen
+ Burn Chroma Chroma brennen
+ Burn Color Farbe brennen
+ Butt cap Flaches Ende
+ Butterworth Butterworth
+ CEA-608 CEA-608
+ CEA-708 CEA-708
+ Cache analysis results for re-use Analyseergebnisse zur Wiederverwendung zwischenspeichern
+ Camera Angle Kamerawinkel
+ Camera Blur Kamera-Weichzeichner
+ Camera Shake Kamerawackeln
+ Capitalisation Groß-/Kleinschreibung
+ Cathedral Kathedrale
+ Cell Pattern Zellmuster
+ Center Channel Pan Panorama des Center-Kanals
+ Center Gradient Verlauf zur Mitte
+ Center Input Center-Eingang
+ Center Out Von der Mitte nach außen
+ Center Point (Latitude) Mittelpunkt (Breitengrad)
+ Center Point (Longitude) Mittelpunkt (Längengrad)
+ Center Split Mittelteilung
+ Center of Sphere Kugelmittelpunkt
+ Cents Cent
+ Change to Color In Farbe ändern
+ Changes are copied in the background a moment after each edit. If FilmCraft quits unexpectedly, they are offered the next time it starts. Änderungen werden kurz nach jeder Bearbeitung im Hintergrund kopiert. Wird FilmCraft unerwartet beendet, werden sie beim nächsten Start angeboten.
+ Channel Kanal
+ Channel Blur Kanal-Weichzeichner
+ Channel Mix Kanalmischung
+ Channel Mixer Kanalmixer
+ Chaos Chaos
+ Chebyshev Tschebyscheff
+ Checker Wipe Schachbrett-Wischblende
+ Checkerboard Schachbrett
+ Chinese Chinesisch
+ Choke Verengen
+ Chorus Chorus
+ Chorus/Flanger Chorus/Flanger
+ Chroma Chroma
+ Chroma Leak Chroma-Leck
+ Chromatic Aberration (Blue) Chromatische Aberration (Blau)
+ Chromatic Aberration (Green) Chromatische Aberration (Grün)
+ Chromatic Aberration (Red) Chromatische Aberration (Rot)
+ Cineon Converter Cineon-Konverter
+ Circle Kreis
+ Clarity Klarheit
+ Clean Combo Clean-Combo
+ Clean Up Noisy Dialogue Verrauschte Dialoge bereinigen
+ Clear Muddiness Dumpfheit entfernen
+ Client Kunde
+ Clip Level Clippegel
+ Clipping Übersteuerung
+ Clock Wipe Uhr-Wischblende
+ Clock Wipe (Legacy) Uhr-Wischblende (alt)
+ Clockwise Im Uhrzeigersinn
+ Clone Klonen
+ Closed Captions Untertitel (Closed Captions)
+ Color & Alpha Farbe und Alpha
+ Color 1 Farbe 1
+ Color 2 Farbe 2
+ Color 3 Farbe 3
+ Color 4 Farbe 4
+ Color Balance Farbbalance
+ Color Burn Farbig nachbelichten
+ Color Channel Farbkanal
+ Color Correction Farbkorrektur
+ Color Distortion Farbverzerrung
+ Color Dodge Farbig abwedeln
+ Color Emboss Farbprägen
+ Color Key Farb-Key
+ Color Pass Farbe durchlassen
+ Color Replace Farbe ersetzen
+ Color Space Farbraum
+ Color Theme Farbschema
+ Color To Leave Beizubehaltende Farbe
+ Color Tolerance Farbtoleranz
+ Color Wheels & Match Farbräder und Abgleich
+ Colorize Färben
+ Columns Spalten
+ Comment Kommentar
+ Complexity Komplexität
+ Composite In Back Dahinter zusammensetzen
+ Composite In Front Davor zusammensetzen
+ Composite Using Zusammensetzen mit
+ Composite on Original Über Original zusammensetzen
+ Compound Blur Zusammengesetzte Weichzeichnung
+ Compression Before Clipping Kompression vor dem Clipping
+ Constant Gain Konstante Verstärkung
+ Constant Power Konstante Leistung
+ Conversion Type Konvertierungsart
+ Convolution Reverb Faltungshall
+ Cool Blue Kühles Blau
+ Cool, desaturated and punchy Kühl, entsättigt und kräftig
+ Core Width Kernbreite
+ Corner Ecke
+ Corner Pin Eckpunkte
+ Count Anzahl
+ Counter-clockwise Gegen den Uhrzeigersinn
+ Crash Recovery Absturzwiederherstellung
+ Crawl Left Nach links laufen
+ Crawl Right Nach rechts laufen
+ Create folder for imported projects Ordner für importierte Projekte erstellen
+ Creative Kreativ
+ Crop Zuschneiden
+ Crop Less <-> Smooth More Weniger zuschneiden <-> Stärker glätten
+ Cross Displacement Kreuzverschiebung
+ Cross Dissolve Weiche Blende
+ Cross Dissolve (Legacy) Weiche Blende (alt)
+ Cross Zoom Kreuzzoom
+ Cross Zoom (Legacy) Kreuzzoom (alt)
+ Crossfade Überblendung
+ Crossovers Übergangsfrequenzen
+ Crystallize Kristallisieren
+ Crystals Kristalle
+ Cube Spin Würfeldrehung
+ Curl Radius Rollradius
+ Current Time Aktuelle Zeit
+ Cursor Cursor
+ Curvature Krümmung
+ Curve Kurve
+ Curves Kurven
+ Custom Benutzerdefiniert
+ Custom Color Benutzerdefinierte Farbe
+ Cutoff Grenzfrequenz
+ Cyan-teal shadows and warm highlights with a little more contrast Cyan-grünliche Tiefen und warme Lichter mit etwas mehr Kontrast
+ Cycle (in Revolutions) Zyklus (in Umdrehungen)
+ Cycle Evolution Zyklische Entwicklung
+ Damping Dämpfung
+ Damping HF Höhendämpfung
+ Damping LF Tiefendämpfung
+ Darken Abdunkeln
+ Darker Color Dunklere Farbe
+ Date Created Erstellungsdatum
+ Date Modified Änderungsdatum
+ Day for night: darker, cooler and less saturated Day for Night: dunkler, kühler und weniger gesättigt
+ DeEsser De-Esser
+ DeHummer Brummentferner
+ DeNoise Entrauscher
+ DeReverb Hallentferner
+ Decay Abklingen
+ Decay Time (RT60) Abklingzeit (RT60)
+ Default Audio Tracks Standard-Audiospuren
+ Default Emoji font Standard-Emoji-Schrift
+ Default Media Scaling Standard-Medienskalierung
+ Default Output Standardausgang
+ Default closed caption font Standardschrift für Closed Captions
+ Default language Standardsprache
+ Default paragraph direction Standard-Absatzrichtung
+ Default subtitle and text font Standardschrift für Untertitel und Text
+ Delay Delay
+ Delay 1 Delay 1
+ Delay 2 Delay 2
+ Delay 3 Delay 3
+ Delay 4 Delay 4
+ Delay and Echo Delay und Echo
+ Delete files older than Dateien löschen, die älter sind als
+ Delete oldest files when the cache exceeds Älteste Dateien löschen, wenn der Cache größer wird als
+ Delete… Löschen…
+ Depth Tiefe
+ Desaturate Entsättigen
+ Description Beschreibung
+ Detail Amplitude Detailamplitude
+ Detail Level Detailgrad
+ Detailed Analysis Detaillierte Analyse
+ Device Class Geräteklasse
+ Dialogue Dialog
+ Diamond Raute
+ Difference Differenz
+ Dimensions Abmessungen
+ Dimmed Abgedunkelt
+ Dip to Black Über Schwarz blenden
+ Dip to Black (Legacy) Über Schwarz blenden (alt)
+ Dip to Color Über Farbe blenden
+ Dip to White Über Weiß blenden
+ Dip to White (Legacy) Über Weiß blenden (alt)
+ Direction Richtung
+ Directional Gerichtet
+ Directional Blur Richtungsunschärfe
+ Directional Blur (Legacy) Richtungsunschärfe (alt)
+ Disable video output when in the background Videoausgabe im Hintergrund deaktivieren
+ Disperse Streuen
+ Displacement Verschiebung
+ Display Color Management Farbmanagement der Anzeige
+ Display Color Settings Farbeinstellungen der Anzeige
+ Display out of sync indicators for unlinked clips Asynchronitätsanzeige für nicht verknüpfte Clips anzeigen
+ Dissolve Auflösen
+ Dissolve Blocks Auflösungsblöcke
+ Distance Abstand
+ Distance to Image Abstand zum Bild
+ Distort Verzerren
+ Distortion Verzerrung
+ Distortion Complexity Komplexität der Verzerrung
+ Distortion Rate Geschwindigkeit der Verzerrung
+ Distortion Type Verzerrungsart
+ Divide Dividieren
+ Do not delete cache files automatically Cachedateien nicht automatisch löschen
+ Don't label speakers Sprecher nicht kennzeichnen
+ Double-click Doppelklick
+ Draft decoding at reduced playback resolution (H.264: faster, some frames less filtered) Entwurfsdekodierung bei reduzierter Wiedergabeauflösung (H.264: schneller, manche Frames weniger gefiltert)
+ Drive Drive
+ Drop Shadow Schlagschatten
+ Dry Dry
+ Dry Out Dry-Ausgang
+ Dry Up a Roomy Voice Hallige Stimme trockener machen
+ Duck Deep Under Dialogue Stark unter Dialog absenken
+ Duck Under Dialogue Unter Dialog absenken
+ Duck Under Voice and Effects Unter Stimme und Effekte absenken
+ Ducking Ducking
+ Dutch Niederländisch
+ Dynamic Link Dynamic Link
+ Dynamics Processing Dynamikbearbeitung
+ Early Reflections Frühe Reflexionen
+ Earthquake Erdbeben
+ Ease In and Out Ease In und Ease Out
+ Easing Easing
+ Echo Echo
+ Echo Glow Echo-Glühen
+ Echo Operator Echo-Operator
+ Echo Time (seconds) Echozeit (Sekunden)
+ Echoes Echos
+ Edge Color Kantenfarbe
+ Edge Feather Weiche Kante
+ Edge Glow Kantenglühen
+ Edge Sharpness Kantenschärfe
+ Edge Softness Kantenweichheit
+ Edge Thickness Kantenstärke
+ Edge Thin Kante verdünnen
+ Edge Threshold Kantenschwellenwert
+ Edge Type Kantentyp
+ Edge Width Kantenbreite
+ Elliptical Elliptisch
+ Emboss Prägen
+ Enable HSL Secondary HSL-Sekundär aktivieren
+ Enable Mercury Transmit Mercury Transmit aktivieren
+ Enable ProRes hardware accelerated encoding, if available Hardwarebeschleunigte ProRes-Kodierung aktivieren, falls verfügbar
+ Enable clip and XMP metadata linking Verknüpfung von Clip- und XMP-Metadaten aktivieren
+ Enable developer mode Entwicklermodus aktivieren
+ Enable hardware accelerated decoding (requires restart) Hardwarebeschleunigte Dekodierung aktivieren (Neustart erforderlich)
+ Enable language auto-detection Automatische Spracherkennung aktivieren
+ Enable proxies Proxys aktivieren
+ End Color Endfarbe
+ End Point Endpunkt
+ End of Ramp Ende des Verlaufs
+ Error Fehler
+ Evolution Entwicklung
+ Evolution Options Entwicklungsoptionen
+ Exciter Amount Exciter-Stärke
+ Exciter Mode Exciter-Modus
+ Exclusion Ausschluss
+ Exponential Fade Exponentielle Blende
+ Extended Dynamic Range Monitoring Überwachung mit erweitertem Dynamikumfang
+ FFT Filter FFT-Filter
+ Fade Blende
+ Fade Out Ausblenden
+ Faded Matte Verblasster Matte-Look
+ Falloff Abfall
+ Far Away Weit entfernt
+ Fast Schnell
+ Faster Motion Schnellere Bewegung
+ Feedback Feedback
+ Feedback 1 Feedback 1
+ Feedback 2 Feedback 2
+ Feedback 3 Feedback 3
+ Feedback 4 Feedback 4
+ Feet + Frames 16mm Fuß + Frames 16 mm
+ Feet + Frames 35mm Fuß + Frames 35 mm
+ Female Weiblich
+ File Size Dateigröße
+ Fill Background Hintergrund füllen
+ Fill Color Füllfarbe
+ Fill Left with Right Links mit rechts füllen
+ Fill Point Füllpunkt
+ Fill Right with Left Rechts mit links füllen
+ Fill Selector Füllauswahl
+ Film Dissolve Filmblende
+ Film Dissolve (Legacy) Filmblende (alt)
+ Film Roll Filmrolle
+ Filter Filter
+ Filter Frequency Filterfrequenz
+ Filter Resonance Filterresonanz
+ Filter and EQ Filter und EQ
+ Final Delay Letztes Delay
+ Find Edges Kanten finden
+ Flanger Flanger
+ Flare Lichtreflex
+ Flare Brightness Helligkeit des Lichtreflexes
+ Flare Center Mitte des Lichtreflexes
+ Flare Color Farbe des Lichtreflexes
+ Flash Aufblitzen
+ Flicker Flackern
+ Flickers Flackern
+ Flip Motion Klappbewegung
+ Flip Over Umklappen
+ Float Gleitkomma
+ Focus Fokus
+ Focus Blur Fokusunschärfe
+ Focus Point Fokuspunkt
+ Focus Shape Fokusform
+ Focus Size Fokusgröße
+ Fold Motion Faltbewegung
+ Foldback Foldback
+ For color management parameters, go to the Settings tab in the Lumetri Color panel. Die Parameter für das Farbmanagement findest du auf dem Reiter „Einstellungen“ des Bedienfelds „Lumetri-Farbe“.
+ Format Format
+ Four Scopes (RGB, 8 bit) Vier Scopes (RGB, 8 Bit)
+ Four Scopes (YUV, float, no clamp) Vier Scopes (YUV, Gleitkomma, unbegrenzt)
+ Fractal Influence Fraktaler Einfluss
+ Fractal Type Fraktaltyp
+ Frame Frame
+ Frame Color Rahmenfarbe
+ Frame Count Anzahl der Frames
+ Frame Layout Frame-Layout
+ Frame Rate Framerate
+ Frame Width Rahmenbreite
+ Frame cache for monitors and thumbnails Frame-Cache für Monitore und Miniaturen
+ Frames Frames
+ Framing Bildausschnitt
+ French Französisch
+ Frequency Frequenz
+ From Von
+ From East Von Osten
+ From North Von Norden
+ From South Von Süden
+ From West Von Westen
+ From the Left Von links
+ From the Right Von rechts
+ Front + LFE Front + LFE
+ Front + Rear Front + Surround
+ Front + Rear + LFE Front + Surround + LFE
+ Front Only Nur Front
+ Fuzz Fuzz
+ GB GB
+ Gamma Gamma
+ Gamma Correction Gammakorrektur
+ Gamut Warning Gamutwarnung
+ Gamut Warning Color Farbe der Gamutwarnung
+ Gap Lücke
+ Gap Color Lückenfarbe
+ Gaussian Blur Gaußscher Weichzeichner
+ Gaussian Blur (Legacy) Gaußscher Weichzeichner (alt)
+ General Allgemein
+ Generate Erzeugen
+ Generate Timecode Timecode erzeugen
+ Generate waveforms and conform audio using multithreading Wellenformen erzeugen und Audio angleichen mit mehreren Threads
+ Generate waveforms automatically during import Wellenformen beim Import automatisch erzeugen
+ German Deutsch
+ Ghosts Geisterbilder
+ Glass Glas
+ Glint Glitzern
+ Glitch Glitch
+ Glow Glühen
+ Glow Brightness Helligkeit des Glühens
+ Glow Color Farbe des Glühens
+ Glow Only Nur Glühen
+ Glow Radius Radius des Glühens
+ Glow Saturation Sättigung des Glühens
+ Glow Width Breite des Glühens
+ Golden Hour Goldene Stunde
+ Good Gut
+ Gradient Farbverlauf
+ Gradient End Verlaufsende
+ Gradient Layer Verlaufsebene
+ Gradient Placement Verlaufsplatzierung
+ Gradient Scatter Verlaufsstreuung
+ Gradient Shape Verlaufsform
+ Gradient Start Verlaufsanfang
+ Gradient Wipe Verlaufswischblende
+ Gradient Wipe (Legacy) Verlaufswischblende (alt)
+ Grain Size Korngröße
+ Graphic Equalizer (10 Bands) Grafischer Equalizer (10 Bänder)
+ Graphic Equalizer (20 Bands) Grafischer Equalizer (20 Bänder)
+ Graphic Equalizer (30 Bands) Grafischer Equalizer (30 Bänder)
+ Graphics Grafiken
+ Green Blurriness Unschärfe Grün
+ Green Curve Kurve Grün
+ Green Offset Versatz Grün
+ Green Power Potenz Grün
+ Green Slope Steigung Grün
+ Green-Blue Grün-Blau
+ Green-Const Grün-Konst.
+ Green-Green Grün-Grün
+ Green-Red Grün-Rot
+ Grid Raster
+ Grow Ausdehnen
+ Growing Files Wachsende Dateien
+ Grunge Grunge
+ Grunge & Distort Grunge und Verzerrung
+ GuitarSuite GuitarSuite
+ HDR Graphics White (Nits) HDR-Grafikweiß (Nits)
+ HLS Vectorscope + Histogram HLS-Vektorskop + Histogramm
+ HSL Secondary HSL-Sekundär
+ Hard Hart
+ Hard Clip Hartes Clipping
+ Hard Light Hartes Licht
+ Hard Limiter Harter Limiter
+ Hard Mix Hart mischen
+ Hardware decoding Hardwaredekodierung
+ Hardware decoding: Auto uses the system's video decoder (VideoToolbox on macOS, Media Foundation on Windows, VA-API or NVDEC for H.264 and HEVC on Linux) for the streams it supports, and FilmCraft's own decoder for everything else or if the hardware fails. Media that is already open keeps its decoder until it is reopened. Hardwaredekodierung: „Automatisch“ verwendet den Videodecoder des Systems (VideoToolbox unter macOS, Media Foundation unter Windows, VA-API oder NVDEC für H.264 und HEVC unter Linux) für die Streams, die er unterstützt, und den eigenen Decoder von FilmCraft für alles andere oder wenn die Hardware versagt. Bereits geöffnete Medien behalten ihren Decoder, bis sie erneut geöffnet werden.
+ Head Size Kopfgröße
+ Heart Herz
+ Height Höhe
+ Hexagon Sechseck
+ Hide Back Face Rückseite ausblenden
+ High Hoch
+ High Cutoff Obere Grenzfrequenz
+ High Frequency Cut Höhenschnitt
+ High Frequency Damping Höhendämpfung
+ High Pass Hochpass
+ High Shelf High-Shelf
+ High Shelf Gain High-Shelf-Verstärkung
+ High contrast with held highlights and deep shadows Hoher Kontrast mit gehaltenen Lichtern und tiefen Schatten
+ Highlight Glanzlicht
+ Highlight Blue Balance Blaubalance der Lichter
+ Highlight Brightness Helligkeit der Lichter
+ Highlight Color Hervorhebungsfarbe
+ Highlight Green Balance Grünbalance der Lichter
+ Highlight Red Balance Rotbalance der Lichter
+ Highlight Rolloff Lichter-Roll-off
+ Highlight Threshold Schwellenwert der Lichter
+ Highlight Tint Tönung der Lichter
+ Highlights Lightness Lichter: Helligkeit
+ Highpass Hochpass
+ Hindi Hindi
+ Hindi digits Hindi-Ziffern
+ Horizontal 16:9 Horizontal 16:9
+ Horizontal Alignment Horizontale Ausrichtung
+ Horizontal Blocks Horizontale Blöcke
+ Horizontal Decentering Horizontale Dezentrierung
+ Horizontal Displacement Horizontale Verschiebung
+ Horizontal Flip Horizontal spiegeln
+ Horizontal Margin Horizontaler Rand
+ Horizontal and Vertical Horizontal und vertikal
+ Hue Center Farbtonmitte
+ Hue Tolerance Farbtontoleranz
+ I/O Buffer Size E/A-Puffergröße
+ Ignore Alpha Alpha ignorieren
+ Image Control Bildsteuerung
+ Immersive Video Immersives Video
+ Import numbered stills as image sequences Nummerierte Standbilder als Bildsequenzen importieren
+ Impulse Impuls
+ In a Room In einem Raum
+ In the Media Cache Im Mediencache
+ In the project Im Projekt
+ In/Out Duration Dauer In bis Out
+ Include captions on import Untertitel beim Import einschließen
+ Incoming Eingehend
+ Indeterminate Media Timebase Unbestimmte Medien-Zeitbasis
+ Initial Delay Anfangs-Delay
+ Inner Innen
+ Inner Radius Innenradius
+ Input Boost Eingangsanhebung
+ Inset Einsatz
+ Inside Innen
+ Inside Color Innenfarbe
+ Inter Inter
+ Interior Room Tone Raumton (innen)
+ Internal Black Point Interner Schwarzpunkt
+ Internal White Point Interner Weißpunkt
+ Interpolation Interpolation
+ Intersect Schnittmenge
+ Inverse Falloff Umgekehrter Abfall
+ Invert Umkehren
+ Invert Alpha Alpha umkehren
+ Invert Blur Weichzeichnung umkehren
+ Invert Fill Füllung umkehren
+ Invert Gradient Verlauf umkehren
+ Invert Left Links umkehren
+ Invert Right Rechts umkehren
+ Iris Box Iris (Rechteck)
+ Iris Cross Iris (Kreuz)
+ Iris Diamond Iris (Raute)
+ Iris Radius Irisradius
+ Iris Rotation Irisdrehung
+ Iris Round Iris (rund)
+ Iris Shape Irisform
+ Italian Italienisch
+ Japanese Japanisch
+ JetBrains Mono JetBrains Mono
+ Join Through Edits Durchgehende Schnitte zusammenfügen
+ Ripple Trim In Ripple-Trimmen am In-Punkt
+ Ripple Trim Out Ripple-Trimmen am Out-Punkt
+ Roll Edit Rollen-Bearbeitung
+ Trim In In-Punkt trimmen
+ Trim Out Out-Punkt trimmen
+ Kaleidoscope Kaleidoskop
+ Keep a recovery copy of unsaved changes Wiederherstellungskopie nicht gespeicherter Änderungen behalten
+ Key Color Key-Farbe
+ Keying Keying
+ Korean Koreanisch
+ Label Defaults Standard-Farbmarkierungen
+ Label speakers Sprecher kennzeichnen
+ Labels Farbmarkierungen
+ Large Hall Große Halle
+ Large Trim Offset Großer Trimmversatz
+ Large Volume Adjustment Große Lautstärkeanpassung
+ Latch Latch
+ Layer Name Ebenenname
+ Layers Ebenen
+ Leave Color Farbe beibehalten
+ Left - Left Links – links
+ Left - Right Links – rechts
+ Left channel to device output Linker Kanal auf Geräteausgang
+ Left to Right Von links nach rechts
+ Left to right Von links nach rechts
+ Legacy Alte Versionen
+ Length Länge
+ Lens Blur Objektivunschärfe
+ Lens Distortion Objektivverzerrung
+ Lens Flare Blendenfleck
+ Lens Type Objektivtyp
+ Level 1 Ebene 1
+ Level 2 Ebene 2
+ Level 3 Ebene 3
+ Level 4 Ebene 4
+ Levels Tonwerte
+ Lifted blacks, softer contrast, muted colour Angehobene Schwarztöne, weicherer Kontrast, gedämpfte Farben
+ Light 1 Licht 1
+ Light 2 Licht 2
+ Light 3 Licht 3
+ Light 4 Licht 4
+ Light 5 Licht 5
+ Light Angle Lichtwinkel
+ Light Color Lichtfarbe
+ Light Intensity Lichtintensität
+ Light Leak Lichteinfall
+ Light Leaks Lichteinfälle
+ Light Sweep Lichtschweif
+ Light Type Lichtart
+ Lighten Aufhellen
+ Lighter Color Hellere Farbe
+ Lighting Effects Beleuchtungseffekte
+ Lightning Blitz
+ Lights & Blurs Licht und Weichzeichnung
+ Lights & Glows Licht und Glühen
+ Line Thickness Linienstärke
+ Linear Burn Linear nachbelichten
+ Linear Dodge (Add) Linear abwedeln (Addieren)
+ Linear Light Lineares Licht
+ Linear Ramp Linearer Verlauf
+ Linear Wipe Lineare Wischblende
+ Linear Wipe (Legacy) Lineare Wischblende (alt)
+ Linear keyframe thinning Lineares Ausdünnen von Keyframes
+ Linear to Log Linear zu Log
+ Liquid Distortion Flüssige Verzerrung
+ Local Projects Lokale Projekte
+ Location Speicherort
+ Log Note Protokollnotiz
+ Log to Linear Log zu Linear
+ Log to Log Log zu Log
+ Logo Cutout Logo-Aussparung
+ Long Shadow Langer Schatten
+ Look-Ahead Time Vorausschauzeit
+ Loudness Lautheit
+ Loudness Maximizer Lautheitsmaximierer
+ Loudness Meter Lautheitsmesser
+ Louver Lamellen
+ Low Niedrig
+ Low Frequency Cut Tiefenschnitt
+ Low Pass Tiefpass
+ Low Shelf Low-Shelf
+ Low Shelf Gain Low-Shelf-Verstärkung
+ Lower Left Unten links
+ Lower Right Unten rechts
+ Lowpass Tiefpass
+ Luma Luma
+ Luma Curve Luma-Kurve
+ Luma Fade Luma-Blende
+ Luma Key Luma-Key
+ Luma Source Luma-Quelle
+ Luma and Chroma Luma und Chroma
+ Lumetri Presets Lumetri-Vorgaben
+ Luminance Luminanz
+ Luminance Threshold Luminanzschwellenwert
+ Luminosity Luminanz
+ MB MB
+ Magnify Vergrößern
+ Magnify (Legacy) Vergrößern (alt)
+ Maintain pitch while shuttling Tonhöhe beim Shuttlen beibehalten
+ Major Radius Großer Radius
+ Male Männlich
+ Map Black To Schwarz zuordnen zu
+ Map White To Weiß zuordnen zu
+ Maps full-range levels into 16–235 (video range) with a luma curve Bildet Pegel des vollen Bereichs mit einer Luma-Kurve auf 16–235 (Videobereich) ab
+ Mask Only Nur Maske
+ Master Amplitude Gesamtamplitude
+ Mastering Mastering
+ Match frame sets in point Quellbild finden setzt In-Punkt
+ Matte Matte
+ Matte Alpha Matte-Alpha
+ Matte Cleanup Matte-Bereinigung
+ Matte Generation Matte-Erzeugung
+ Matte Luma Matte-Luma
+ Maximum Maximum
+ Maximum Amplitude Maximale Amplitude
+ Maximum Block Size Maximale Blockgröße
+ Maximum Blur Maximale Weichzeichnung
+ Maximum Project Versions Maximale Anzahl an Projektversionen
+ Maximum Reduction Maximale Absenkung
+ Maximum Scale Maximale Skalierung
+ Media Medien
+ Media Analysis Medienanalyse
+ Media Analysis & Transcription Medienanalyse und Transkription
+ Media Cache Mediencache
+ Media Cache Database Mediencache-Datenbank
+ Media Cache Files Mediencache-Dateien
+ Media Cache Management Mediencache-Verwaltung
+ Media Duration Mediendauer
+ Media End Medienende
+ Media Time Medienzeit
+ Media Timecode Medien-Timecode
+ Media Type Medientyp
+ Media analysis and transcriptions will be cached in the Media Cache folder. Reanalysis won't be required if the media is imported into another project on this computer. Medienanalysen und Transkriptionen werden im Mediencache-Ordner zwischengespeichert. Wird das Medium auf diesem Computer in ein anderes Projekt importiert, ist keine neue Analyse nötig.
+ Median Median
+ Medium Room Mittlerer Raum
+ Memory Arbeitsspeicher
+ Metadata & Timecode Burn-in Metadaten und Timecode einbrennen
+ Method Methode
+ Metrics Kerning Metrische Unterschneidung
+ Mid Mitten
+ Mid Point Mittelpunkt
+ Midtone Blue Balance Blaubalance der Mitteltöne
+ Midtone Green Balance Grünbalance der Mitteltöne
+ Midtone Red Balance Rotbalance der Mitteltöne
+ Midtones Lightness Mitteltöne: Helligkeit
+ Minimum Minimum
+ Minimum time Mindestzeit
+ Minimum time interval thinning Ausdünnen nach Mindestzeitabstand
+ Minor Radius Kleiner Radius
+ Mirror Spiegeln
+ Mirror Alternate Abwechselnd spiegeln
+ Missing font replacement Ersatz für fehlende Schriften
+ Miter join Spitze Ecke
+ Miter limit Gehrungsgrenze
+ Mixed Crystals Gemischte Kristalle
+ Mode Modus
+ Modern High Gain Moderner High-Gain
+ Modulation Modulation
+ Modulation Rate Modulationsrate
+ Mono Media Mono-Medien
+ Monochrome Monochrom
+ Monochrome toned cyan-blue Monochrom, cyanblau getönt
+ Monochrome toned warm brown Monochrom, warmbraun getönt
+ Monoscopic Monoskopisch
+ Monospace only Nur dicktengleiche Schriften
+ More colour in the less saturated areas Mehr Farbe in weniger gesättigten Bereichen
+ Morph Cut Morph-Schnitt
+ Mosaic Mosaik
+ Mosaic (Legacy) Mosaik (alt)
+ Motion Blur Bewegungsunschärfe
+ Motion Camera Kamerabewegung
+ Motion Preset Bewegungsvorgabe
+ Motion Tween Bewegungs-Tween
+ Move Verschieben
+ Movie Film
+ Movie (audio and video) Film (Audio und Video)
+ Multiband Compressor Multiband-Kompressor
+ Multichannel Mono Media Mehrkanal-Mono-Medien
+ Multiply Multiplizieren
+ Multitap Delay Multitap-Delay
+ Music Musik
+ Mute input during timeline recording Eingang während der Timeline-Aufnahme stummschalten
+ Name Name
+ Narrow Schmal
+ Neon Color Neonfarbe
+ Neon Wipe Neon-Wischblende
+ Next to original media files Neben den Original-Mediendateien
+ Night Nacht
+ No Motion Keine Bewegung
+ No Scroll Kein Bildlauf
+ No plugins are installed. Changes will take effect the next time you start FilmCraft. Es sind keine Plug-ins installiert. Änderungen werden beim nächsten Start von FilmCraft wirksam.
+ Noise Rauschen
+ Noise & Grain Rauschen und Körnung
+ Noise (Legacy) Rauschen (alt)
+ Noise Level Rauschpegel
+ Noise Reduction/Restoration Rauschunterdrückung/Restaurierung
+ Noise Type Rauschtyp
+ Non-Additive Dissolve Nicht-additive Blende
+ Normal Normal
+ Notch 1 Notch 1
+ Notch 2 Notch 2
+ Notch 3 Notch 3
+ Notch 4 Notch 4
+ Notch 5 Notch 5
+ Notch 6 Notch 6
+ Notch Filter Notch-Filter
+ Notch Width Notch-Breite
+ Number Of Echoes Anzahl der Echos
+ Number of Harmonics Anzahl der Obertöne
+ Obsolete Veraltet
+ Octagon Achteck
+ Offset Versatz
+ Offset (Turbulence) Versatz (Turbulenz)
+ Offset From Versatz von
+ Offset To Versatz bis
+ Omni Omni
+ On An
+ On Original Image Auf Originalbild
+ On Transparent Auf Transparenz
+ Open Air Freiluft
+ Open Most Recent Zuletzt verwendetes öffnen
+ Open in new window In neuem Fenster öffnen
+ Open in place An Ort und Stelle öffnen
+ Open new tab Neuen Tab öffnen
+ Opens up the shadows Hellt die Tiefen auf
+ Order Reihenfolge
+ Orientation Ausrichtung
+ Outer Außen
+ Outgoing Ausgehend
+ Output Ausgang
+ Output Mapping Ausgangszuordnung
+ Outside Außen
+ Outside Color Außenfarbe
+ Overflow Überlauf
+ Overlay Überlagern
+ Overshoot Überschwingen
+ Page Peel Seite ablösen
+ Page Scroll Seite rollen
+ Page Turn Seite umblättern
+ Paint Bucket Farbeimer
+ Paint On Black Auf Schwarz malen
+ Paint On Original Image Auf Originalbild malen
+ Paint On Transparent Auf Transparenz malen
+ Paint On White Auf Weiß malen
+ Paint Style Malstil
+ Paint Surface Malfläche
+ Pan (Y Axis) Schwenk (Y-Achse)
+ Panel Wipe Feld-Wischblende
+ Panels Bedienfelder
+ Panner - Ambisonics Panner – Ambisonics
+ Parade Parade
+ Parade (RGB) Parade (RGB)
+ Parametric Equalizer Parametrischer Equalizer
+ Passband Ripple Welligkeit im Durchlassbereich
+ Path Pfad
+ Path Points Pfadpunkte
+ Pause Media Encoder queue during playback Media-Encoder-Warteschlange während der Wiedergabe anhalten
+ Peak Frequency Spitzenfrequenz
+ Peak Gain Spitzenverstärkung
+ Pedestal Schwarzabhebung
+ Pentagon Fünfeck
+ Per line Pro Zeile
+ Percent Blur Weichzeichnung in Prozent
+ Perspective Perspektive
+ Phase Difference Phasendifferenz
+ Phaser Phaser
+ Phone Call Telefonanruf
+ Phosphor Phosphor
+ Phosphor Color Phosphorfarbe
+ Photocopy Fotokopie
+ Photocopy Color Fotokopie-Farbe
+ Pillow Kissen
+ Pin All Alle anheften
+ Pin Horizontal Horizontal anheften
+ Pin Light Lichtpunkt
+ Pin Vertical Vertikal anheften
+ Pinning Anheften
+ Pitch Shifter Tonhöhenverschiebung
+ Plate Platte
+ Plateau Wipe Plateau-Wischblende
+ Plateaus Plateaus
+ Plates Platten
+ Play after rendering previews Nach dem Rendern der Vorschau abspielen
+ Play audio while scrubbing in Source and Program Monitors Audio beim Scrubben in Quell- und Programmmonitor abspielen
+ Playback Wiedergabe
+ Playhead position determines trim monitor loop playback Die Abspielposition bestimmt die Schleifenwiedergabe im Trimmmonitor
+ Plugins Plug-ins
+ Podcast Voice Podcast-Stimme
+ Point 1 Punkt 1
+ Point 1 Color Farbe Punkt 1
+ Point 1 Latitude Breitengrad Punkt 1
+ Point 1 Longitude Längengrad Punkt 1
+ Point 2 Punkt 2
+ Point 2 Color Farbe Punkt 2
+ Point 2 Latitude Breitengrad Punkt 2
+ Point 2 Longitude Längengrad Punkt 2
+ Point 3 Punkt 3
+ Point 3 Color Farbe Punkt 3
+ Point 3 Latitude Breitengrad Punkt 3
+ Point 3 Longitude Längengrad Punkt 3
+ Point 4 Punkt 4
+ Point 5 Punkt 5
+ Point 6 Punkt 6
+ Point 7 Punkt 7
+ Point 8 Punkt 8
+ Points Punkte
+ Policy Richtlinie
+ Pop Motion Aufspringende Bewegung
+ Portuguese Portugiesisch
+ Position & Rotation Position und Drehung
+ Position Amount Positionsstärke
+ Position, Scale & Rotation Position, Skalierung und Drehung
+ Position, Scale, Rotation Position, Skalierung, Drehung
+ Posterize Tontrennung
+ Posterize Time Zeitliche Tontrennung
+ Pre-Delay Pre-Delay
+ Prefix Präfix
+ Presence Lift Präsenzanhebung
+ Preserve Luminosity Luminanz erhalten
+ Preserve Scale Skalierung erhalten
+ ProcAmp ProcAmp
+ Projecting cap Überstehendes Ende
+ Projects Projekte
+ Pull Motion Ziehbewegung
+ Pulls highlights and whites down Senkt Lichter und Weißtöne ab
+ Push Wegschieben
+ Push (Legacy) Wegschieben (alt)
+ Q Q
+ RAM reserved for other applications Für andere Programme reservierter Arbeitsspeicher
+ RGB RGB
+ RGB Split RGB-Trennung
+ RGB-White RGB-Weiß
+ Radial Radial
+ Radial Blur Radialer Weichzeichner
+ Radial Ramp Radialer Verlauf
+ Radial Wipe Radiale Wischblende
+ Radial Wipe (Legacy) Radiale Wischblende (alt)
+ Radio Announcer Radiosprecher
+ Radio Voice Radiostimme
+ Radius Radius
+ Ramp Verlauf
+ Ramp Shape Verlaufsform
+ Random Zufällig
+ Random Seed Zufallsstartwert
+ Range Bereich
+ Ray Strahl
+ Ray Color Strahlfarbe
+ Ray Length Strahllänge
+ Rays Strahlen
+ Rays Only Nur Strahlen
+ Read Lesen
+ Rec. 2100 Rec. 2100
+ Rec. 601 Rec. 601
+ Rec. 709 Rec. 709
+ Red Blurriness Unschärfe Rot
+ Red Curve Kurve Rot
+ Red Offset Versatz Rot
+ Red Power Potenz Rot
+ Red Slope Steigung Rot
+ Red-Blue Rot-Blau
+ Red-Const Rot-Konst.
+ Red-Green Rot-Grün
+ Red-Red Rot-Rot
+ Reduce Axis Achse reduzieren
+ Reduce Interlace Flicker Zeilenflimmern reduzieren
+ Reflected Gespiegelt
+ Reflection Angle Spiegelungswinkel
+ Reflection Center Spiegelungsmitte
+ Refraction Brechung
+ Reframe Offset Versatz beim Neu-Framen
+ Reframe Zoom Zoom beim Neu-Framen
+ Refresh growing Files Every Wachsende Dateien aktualisieren alle
+ Relaxed Entspannt
+ Release Time Release-Zeit
+ Relief Relief
+ Remaining Verbleibend
+ Remove Fringe Farbsaum entfernen
+ Render Edit in Audition files to: In Audition bearbeitete Dateien rendern nach:
+ Render audio when rendering video Beim Rendern von Video auch Audio rendern
+ Repair Reparieren
+ Repeat Edge Pixels Randpixel wiederholen
+ Replace Color Farbe ersetzen
+ Replace With Clip From Source Monitor Durch Clip aus dem Quellmonitor ersetzen
+ Replicate Replizieren
+ Responsive Design - Position Responsive Design – Position
+ Responsive Design - Time Responsive Design – Zeit
+ Restore open sequences when opening projects Geöffnete Sequenzen beim Öffnen von Projekten wiederherstellen
+ Result Ergebnis
+ Retro Retro
+ Reveal Nested Sequence Verschachtelte Sequenz anzeigen
+ Reveal Original Image Originalbild anzeigen
+ Reveal in Project Im Projekt anzeigen
+ Reverb Amount Hallanteil
+ Reverse Rückwärts
+ Right - Left Rechts – links
+ Right - Right Rechts – rechts
+ Right channel to device output Rechter Kanal auf Geräteausgang
+ Right to left Von rechts nach links
+ Ripple trim adds edits to keep both sides of trim in sync Ripple-Trimmen fügt Schnitte hinzu, damit beide Seiten synchron bleiben
+ Roll (Z Axis) Rollen (Z-Achse)
+ Room Size Raumgröße
+ Rotation Amount Drehungsstärke
+ Roughen Aufrauen
+ Roughen Color Raue Farbe
+ Roughen Edges Kanten aufrauen
+ Round cap Abgerundetes Ende
+ Round join Abgerundete Ecke
+ Rounded Crop Abgerundeter Zuschnitt
+ Rows Zeilen
+ Russian Russisch
+ Rusty Rostig
+ Rusty Color Rostfarbe
+ SFX Soundeffekte
+ Sample Rate Abtastrate
+ Saturation at 50 % Sättigung bei 50 %
+ Save .cfa and .pek media cache files next to original media files when possible .cfa- und .pek-Mediencachedateien nach Möglichkeit neben den Originalmedien speichern
+ Scale (Degrees) Skalierung (Grad)
+ Scale Amount Skalierungsstärke
+ Scale From Skalieren von
+ Scale Height Höhe skalieren
+ Scale Match Skalierung angleichen
+ Scale To Skalieren auf
+ Scale Width Breite skalieren
+ Scale to frame size Auf Bildgröße skalieren
+ Scan Lines Abtastzeilen
+ Scene Szene
+ Scientific Filter Wissenschaftlicher Filter
+ Scratch disk location for Captured Audio Speicherort des Arbeitslaufwerks für aufgenommenes Audio
+ Screen Umgekehrt multiplizieren
+ Seconds Sekunden
+ Segments Segmente
+ Semi-tones Halbtöne
+ Sequence Name Sequenzname
+ Sequence Timecode Sequenz-Timecode
+ Set focus on the Timeline when performing Insert/Overwrite edits Bei Einfügen/Überschreiben den Fokus auf die Timeline setzen
+ Set to frame size An Bildgröße anpassen
+ Setting Einstellung
+ Shadow Angle Schattenwinkel
+ Shadow Blue Balance Blaubalance der Tiefen
+ Shadow Blur Schattenweichzeichnung
+ Shadow Color Schattenfarbe
+ Shadow Distance Schattenabstand
+ Shadow Green Balance Grünbalance der Tiefen
+ Shadow Only Nur Schatten
+ Shadow Opacity Schattendeckkraft
+ Shadow Red Balance Rotbalance der Tiefen
+ Shadow Size Schattengröße
+ Shadow Tint Tönung der Tiefen
+ Shadows Lightness Tiefen: Helligkeit
+ Shake Schütteln
+ Shape Dissolve Formblende
+ Shape Flow Formfluss
+ Shape Size Formgröße
+ Shapes Formen
+ Shard Size Splittergröße
+ Sharp Colors Scharfe Farben
+ Sharpen Amount Stärke der Scharfzeichnung
+ Shift Center To Mitte verschieben nach
+ Shift clips that overlap trim point during ripple trimming Clips, die den Trimmpunkt überlappen, beim Ripple-Trimmen verschieben
+ Shot Einstellung (Shot)
+ Show "Project:" and "Bin:" in Project panel tab „Projekt:“ und „Ablage:“ im Reiter des Projekt-Bedienfelds anzeigen
+ Show Clip Mismatch Warning dialog Warnung bei nicht passendem Clip anzeigen
+ Show Event Indicator Ereignisanzeige anzeigen
+ Show Focus Area Fokusbereich anzeigen
+ Show Home Startseite anzeigen
+ Show Mask Tracker Preview Vorschau der Maskenverfolgung anzeigen
+ Show Only Noise Nur Rauschen anzeigen
+ Show Open Dialog Öffnen-Dialog anzeigen
+ Show Project Load Error Dialog Fehlerdialog beim Laden von Projekten anzeigen
+ Show Rich Tool Tips Ausführliche QuickInfos anzeigen
+ Show Tool Tips QuickInfos anzeigen
+ Show Workspace Reset Warning dialog on double click Bei Doppelklick Warnung zum Zurücksetzen des Arbeitsbereichs anzeigen
+ Show system compatibility issues at startup Systemkompatibilitätsprobleme beim Start anzeigen
+ Shrink Verkleinern
+ Shutter Angle Verschlusswinkel
+ Similarity Ähnlichkeit
+ Simple Notch Filter Einfacher Notch-Filter
+ Simple Parametric EQ Einfacher parametrischer EQ
+ Simple Text Einfacher Text
+ Single-band Compressor Einband-Kompressor
+ Sinusoidal Sinusförmig
+ Skew Neigen
+ Skew Axis Neigungsachse
+ Slats Latten
+ Slice Scheibe
+ Slices Scheiben
+ Slide Schieben
+ Slide (Legacy) Schieben (alt)
+ Slope Steigung
+ Slow Langsam
+ Slower Motion Langsamere Bewegung
+ Small Room Kleiner Raum
+ Smart Limit Intelligente Begrenzung
+ Smart Tools Intelligente Werkzeuge
+ Smart quotes Typografische Anführungszeichen
+ Smooth Glatt
+ Smooth Motion Gleichmäßige Bewegung
+ Smooth Scroll Sanfter Bildlauf
+ Smoothness Glätte
+ Snap playhead in Timeline when Snap is enabled Abspielposition in der Timeline einrasten, wenn Einrasten aktiviert ist
+ Soft Weich
+ Soft Clamp Weiches Begrenzen
+ Soft Edges (Best Quality) Weiche Kanten (beste Qualität)
+ Soft Light Weiches Licht
+ Soft Wipe Weiche Wischblende
+ Soften Harshness Härte mildern
+ Softness Weichheit
+ Solarize Solarisation
+ Solid Colors Volltonfarben
+ Source Point Quellpunkt
+ Source Text Quelltext
+ Spacer Abstandhalter
+ Spanish Spanisch
+ Speaker Angle Lautsprecherwinkel
+ Speaker Labeling Sprecherkennzeichnung
+ Special Spezial
+ Special Effects Spezialeffekte
+ Speech model Sprachmodell
+ Speed Geschwindigkeit
+ Spherize Kugelisieren
+ Spiky Spitz
+ Spill Farbüberstrahlung
+ Spill Suppression Unterdrückung der Farbüberstrahlung
+ Spin Wirbeln
+ Spin Direction Drehrichtung
+ Spin Motion Drehbewegung
+ Split Teilen
+ Split (Legacy) Teilen (alt)
+ Spotlight Spotlicht
+ Spread Ausbreitung
+ Spring Motion Federnde Bewegung
+ Square Quadrat
+ Square (Width Only) Quadrat (nur Breite)
+ Square 1:1 Quadratisch 1:1
+ Stabilization Stabilisierung
+ Stabilize Only Nur stabilisieren
+ Stabilize, Crop Stabilisieren, zuschneiden
+ Stabilize, Crop, Auto-scale Stabilisieren, zuschneiden, automatisch skalieren
+ Stabilize, Synthesize Edges Stabilisieren, Kanten synthetisieren
+ Stages Stufen
+ Star Stern
+ Star Wipe Stern-Wischblende
+ Start Angle Startwinkel
+ Start Color Startfarbe
+ Start Point Startpunkt
+ Start at 0 Bei 0 beginnen
+ Start at 1 Bei 1 beginnen
+ Start of Ramp Anfang des Verlaufs
+ Start with an Empty Project Mit leerem Projekt beginnen
+ Starting Intensity Anfangsintensität
+ Static Plates Statische Platten
+ Step forward/back many Weit vorwärts/rückwärts
+ Stereo Expand Stereoerweiterung
+ Stereo Expander Stereo-Expander
+ Stereo Imagery Stereobild
+ Stereo Media Stereo-Medien
+ Stereo Phasing Stereo-Phasing
+ Stereoscopic - Over/Under Stereoskopisch – übereinander
+ Stereoscopic - Side by Side Stereoskopisch – nebeneinander
+ Still Standbild
+ Still Image Default Duration Standarddauer für Standbilder
+ Stone Church Steinkirche
+ Stopband Attenuation Sperrbereichsdämpfung
+ Straight Color Direkte Farbe
+ Strength Stärke
+ Stretch Strecken
+ Stretch Gradient to Fit Verlauf einpassen
+ Stretch Map to Fit Map einpassen
+ Stretch Width or Height Breite oder Höhe strecken
+ Stretch Wipe Streck-Wischblende
+ Stretch to Fit Frame Auf Bild strecken
+ Stripe Streifen
+ Stripes Streifen
+ Strobe Color Stroboskopfarbe
+ Strobe Duration (secs) Stroboskopdauer (s)
+ Strobe Light Stroboskoplicht
+ Strobe Period (secs) Stroboskopperiode (s)
+ Stroke 2 Color Farbe Kontur 2
+ Stroke 2 Type Typ Kontur 2
+ Stroke 2 Width Breite Kontur 2
+ Stroke Angle Strichwinkel
+ Stroke Color Konturfarbe
+ Stroke Density Strichdichte
+ Stroke Length Strichlänge
+ Stroke Length (secs) Strichlänge (s)
+ Stroke Only Nur Kontur
+ Stroke Randomness Strichzufälligkeit
+ Stroke Type Konturtyp
+ Stroke Width Konturbreite
+ Stroke line cap Linienende der Kontur
+ Stroke line join Linienverbindung der Kontur
+ Studio Reverb Studiohall
+ Stylize Stilisieren
+ Subclip End Subclip-Ende
+ Subclip Start Subclip-Anfang
+ Subspace Warp Subspace-Verkrümmung
+ Subtitle Untertitel
+ Subtract Subtrahieren
+ Sum multichannel outputs to mono in Source Monitor Mehrkanalausgänge im Quellmonitor zu Mono summieren
+ Super Narrow Extrem schmal
+ Surface Gloss Oberflächenglanz
+ Surface Material Oberflächenmaterial
+ Surround Reverb Surround-Hall
+ Swap Tauschen
+ Swap Channels Kanäle tauschen
+ Swivel Schwenken
+ Synthetic Synthetisch
+ TV Power TV ein/aus
+ Tape Band
+ Tape Name Bandname
+ Tape/Tube Band/Röhre
+ Target Aspect Zielseitenverhältnis
+ Target Color Zielfarbe
+ Target Field of View Ziel-Sichtfeld
+ Target Loudness Ziellautheit
+ Teal & Orange Petrol und Orange
+ Telephone Telefon
+ Teletext Teletext
+ Template Properties Vorlageneigenschaften
+ Text Animator Text-Animator
+ Text Color Textfarbe
+ The media cache holds render previews of unsaved projects and other files FilmCraft can recreate. Deleting them is always safe; FilmCraft rebuilds them as needed. Der Mediencache enthält gerenderte Vorschauen nicht gespeicherter Projekte und andere Dateien, die FilmCraft neu erstellen kann. Sie zu löschen ist immer unbedenklich; FilmCraft erzeugt sie bei Bedarf neu.
+ Thickness Dicke
+ Tile Gradient Gekachelter Verlauf
+ Tilt Neigung
+ Tilt (X Axis) Neigung (X-Achse)
+ Time Zeit
+ Time and Pitch Zeit und Tonhöhe
+ Timecode Conversion Timecode-Umrechnung
+ Timeline Mouse Scrolling Bildlauf der Timeline mit der Maus
+ Timeline Playback Auto-Scrolling Automatischer Bildlauf der Timeline bei der Wiedergabe
+ Tint Color Tönungsfarbe
+ To Bis
+ Tolerance Toleranz
+ Tone Ton
+ Top Center Oben Mitte
+ Top Left Oben links
+ Top Right Oben rechts
+ Touch Touch
+ Track Matte Key Spurmaske-Key
+ Transcription Transkription
+ Transcription preferences Transkriptionseinstellungen
+ Transform Transformieren
+ Transformers Transformer
+ Transience Transienten
+ Transition Completion Übergangsfortschritt
+ Transition Softness Weichheit des Übergangs
+ Transparency Transparenz
+ Trash Papierkorb
+ Travel Motion Reisebewegung
+ Treble Höhen
+ Triangle Dreieck
+ Trim Trimmen
+ Tube Röhre
+ Tube-modeled Compressor Röhrenkompressor
+ Tubular Röhrenförmig
+ Turbulent Turbulent
+ Turbulent Displace Turbulentes Versetzen
+ Turbulent Sharp Turbulent scharf
+ Turbulent Smooth Turbulent weich
+ Turbulent Smoother Turbulent weicher
+ Tweed Tweed
+ Twirl Strudel
+ Twirl (Legacy) Strudel (alt)
+ Twirl Center Strudelmitte
+ Twirl Radius Strudelradius
+ Twist Verdrehung
+ Twist Smoother Verdrehungsglättung
+ Typewriter Schreibmaschine
+ Ultra Key Ultra Key
+ Uniform Scale Gleichmäßige Skalierung
+ Uniform Spacing Gleichmäßiger Abstand
+ Unsharp Mask Unscharf maskieren
+ Update it at least every Mindestens aktualisieren alle
+ Update timeline dynamically during ripple edits. Timeline während Ripple-Bearbeitungen dynamisch aktualisieren.
+ Upper Frequency Obere Frequenz
+ Upper Left Oben links
+ Upper Right Oben rechts
+ Use Color Noise Farbrauschen verwenden
+ Use End Color Endfarbe verwenden
+ Use File Datei verwenden
+ Use Glow Color Glühfarbe verwenden
+ Use Media Source Medienquelle verwenden
+ Use Tint Color Tönungsfarbe verwenden
+ Utility Hilfsmittel
+ VHS Damage VHS-Schaden
+ VR Blur VR-Weichzeichner
+ VR Chroma Leaks VR-Chroma-Lecks
+ VR Chromatic Aberrations VR-Chromatische Aberrationen
+ VR Color Gradients VR-Farbverläufe
+ VR De-Noise VR-Entrauschen
+ VR Digital Glitch VR-Digitaler Glitch
+ VR Fractal Noise VR-Fraktales Rauschen
+ VR Glow VR-Glühen
+ VR Gradient Wipe VR-Verlaufswischblende
+ VR Iris Wipe VR-Iris-Wischblende
+ VR Light Leaks VR-Lichteinfälle
+ VR Light Rays VR-Lichtstrahlen
+ VR Mobius Zoom VR-Möbius-Zoom
+ VR Plane to Sphere VR-Ebene zu Kugel
+ VR Projection VR-Projektion
+ VR Random Blocks VR-Zufällige Blöcke
+ VR Rotate Sphere VR-Kugel drehen
+ VR Sharpen VR-Scharfzeichnen
+ VR Spherical Blur VR-Kugelförmige Weichzeichnung
+ Validate Content Credentials on import Content Credentials beim Import überprüfen
+ Vectorscope (YUV) Vektorskop (YUV)
+ Vectorscope + Waveform YC Vektorskop + Wellenform YC
+ Vectorscope HLS Vektorskop HLS
+ Vectorscope YUV Vektorskop YUV
+ Venetian Blinds Jalousie
+ Vertical 4:5 Vertikal 4:5
+ Vertical 9:16 Vertikal 9:16
+ Vertical Alignment Vertikale Ausrichtung
+ Vertical Blocks Vertikale Blöcke
+ Vertical Decentering Vertikale Dezentrierung
+ Vertical Displacement Vertikale Verschiebung
+ Vertical Flip Vertikal spiegeln
+ Vertical Margin Vertikaler Rand
+ Very Narrow Sehr schmal
+ Video 1 Video 1
+ Video 2 Video 2
+ Video 3 Video 3
+ Video 4 Video 4
+ Video 5 Video 5
+ Video 6 Video 6
+ Video 7 Video 7
+ Video 8 Video 8
+ Video Codec Videocodec
+ Video Duration Videodauer
+ Video Effects Videoeffekte
+ Video In Point Video-In-Punkt
+ Video Info Videoinformationen
+ Video Limiter Videobegrenzer
+ Video Out Point Video-Out-Punkt
+ Video Transition Default Duration Standarddauer für Videoübergänge
+ Video Transitions Videoübergänge
+ Video Usage Videonutzung
+ Vignette Vignette
+ Vivid Light Lebhaftes Licht
+ Vocal Booth Sprecherkabine
+ Vocal Enhancer Stimmverbesserer
+ Voice Stimme
+ Voice in a Hall Stimme in einer Halle
+ Volumetric Rays Volumetrische Strahlen
+ Warm Film Warmer Film
+ Warm Room Warmer Raum
+ Warm Voice Warme Stimme
+ Warm print stock with gentle roll-off Warmes Kopiermaterial mit sanftem Roll-off
+ Warm, soft late-afternoon light Warmes, weiches Licht am späten Nachmittag
+ Warning Warnung
+ Warp Stabilizer Verkrümmungsstabilisierung
+ Wave Welle
+ Wave Height Wellenhöhe
+ Wave Speed Wellengeschwindigkeit
+ Wave Warp Wellenverkrümmung
+ Wave Width Wellenbreite
+ Waveform Wellenform
+ Waveform (Luma) Wellenform (Luma)
+ Waveform (RGB) Wellenform (RGB)
+ Wavelength Wellenlänge
+ Wet Wet
+ Wet Out Wet-Ausgang
+ When Opening a Project Beim Öffnen eines Projekts
+ Whip Reißschwenk
+ Whip (Legacy) Reißschwenk (alt)
+ Whisper base (balanced) Whisper base (ausgewogen)
+ Whisper small (most accurate) Whisper small (am genauesten)
+ Whisper tiny (fastest) Whisper tiny (am schnellsten)
+ White Weiß
+ White Input Level Weißeingangspegel
+ White Is High Weiß ist hoch
+ Wide Outdoor Weite Außenumgebung
+ Widener Verbreiterer
+ Width Breite
+ Wiggle Wackeln
+ Wipe Wischblende
+ Wipe Angle Wischwinkel
+ Wonder Glow Wunderglühen
+ Wrap Back Zurückfalten
+ Write Schreiben
+ Write XMP ID to files on import XMP-ID beim Import in Dateien schreiben
+ Write clip markers to XMP Clipmarker in XMP schreiben
+ Write-on Einschreiben
+ X Rotation X-Drehung
+ Y Rotation Y-Drehung
+ YC YC
+ YC no Chroma YC ohne Chroma
+ YUV YUV
+ Yellow-green highlights and blue-lifted shadows from crossed channel curves Gelbgrüne Lichter und bläulich angehobene Tiefen durch gekreuzte Kanalkurven
+ Z Position Z-Position
+ Z Rotation Z-Drehung
+ Zoom Zoom
+ Zoom Amount Zoomstärke
+ Zoom Blur Zoom-Weichzeichner
+ Zoom Strength Zoomintensität
+ days Tage
+ frames Frames
+ milliseconds Millisekunden
+ minute(s) Minute(n)
+ second(s) Sekunde(n)
+ seconds Sekunden
+ Create Search Bin Suchablage erstellen
+ Edit Offline File Offline-Datei bearbeiten
+ Source Settings Quelleinstellungen
+ Update Metadata Metadaten aktualisieren
+ Automate To Sequence Automatisch in Sequenz einfügen
+ Scene Edit Detection Szenenschnitterkennung
+ Analyze Analysieren
+ Normalize Mix Track Mix-Spur normalisieren
+ Simplify Sequence Sequenz vereinfachen
+ Simplify Vereinfachen
+ Transcribe Sequence Sequenz transkribieren
+ Save as Template Als Vorlage speichern
+ Flash Cue Marker Flash-Cue-Marker
+ System Compatibility Report Systemkompatibilitätsbericht
+ no GPU adapter: the CPU compositor is used kein GPU-Adapter: der CPU-Compositor wird verwendet
+ Avid Log Exchange Avid Log Exchange
+ FilmCraft Project FilmCraft-Projekt
+ {name} Selection.fcproj {name} Auswahl.fcproj
+ {name} (Simplified) {name} (vereinfacht)
+ Find in: Suchen in:
+ Find: Suchen:
+ Search: Suche:
+ Clip Names and Markers Clipnamen und Marker
+ Match: Übereinstimmung:
+ All Alle
+ Any Beliebige
+ Case Sensitive Groß-/Kleinschreibung beachten
+ Scratch Disks Arbeitslaufwerke
+ Ingest Settings Ingest-Einstellungen
+ Captured and Generated: Aufgenommen und erzeugt:
+ Video Previews: Videovorschauen:
+ Audio Previews: Audiovorschauen:
+ Project Auto Save: Automatische Projektspeicherung:
+ Same as Project Wie Projekt
+ Path: {path} Pfad: {path}
+ Transcode Transkodieren
+ Copy and Create Proxies Kopieren und Proxys erstellen
+ Action: Aktion:
+ Destination: Ziel:
+ Next to the media Neben den Medien
+ Video Rendering and Playback Videorendering und -wiedergabe
+ Renderer: Renderer:
+ Display Format: Anzeigeformat:
+ Milliseconds Millisekunden
+ Capture Aufnahme
+ Capture Format: Aufnahmeformat:
+ Action and Title Safe Areas Sichere Aktions- und Titelbereiche
+ Title Safe Area Sicherer Titelbereich
+ Action Safe Area Sicherer Aktionsbereich
+ Total Duration Gesamtdauer
+ Average Data Rate Durchschnittliche Datenrate
+ Colour Farbe
+ {codec} · {rate} Hz · {n} channel(s) {codec} · {rate} Hz · {n} Kanal/Kanäle
+ Media Name: Medienname:
+ Scene: Szene:
+ Shot/Take: Einstellung/Take:
+ Log Note: Protokollnotiz:
+ Codec: {codec} Codec: {codec}
+ Write the metadata of the selected clip(s) ({n}) to XMP files next to their media? Metadaten der ausgewählten Clips ({n}) in XMP-Dateien neben ihren Medien schreiben?
+ Existing XMP files written by other applications are left unchanged. Vorhandene XMP-Dateien anderer Programme bleiben unverändert.
+ To {name} In {name}
+ Ordering: Reihenfolge:
+ Sort Order Sortierreihenfolge
+ Selection Order Auswahlreihenfolge
+ Placement: Platzierung:
+ Sequentially Nacheinander
+ At Unnumbered Markers An nicht nummerierten Markern
+ Method: Methode:
+ Insert Edit Einfügen
+ Overwrite Edit Überschreiben
+ Clip Overlap: Clipüberlappung:
+ Frames per Still: Frames pro Standbild:
+ Transitions Übergänge
+ Apply Default Audio Transition Standard-Audioübergang anwenden
+ Apply Default Video Transition Standard-Videoübergang anwenden
+ Ignore Options Ignorieren-Optionen
+ Ignore Audio Audio ignorieren
+ Ignore Video Video ignorieren
+ Apply a cut at each detected cut point An jedem erkannten Schnittpunkt einen Schnitt setzen
+ Create a bin of subclips from each detected cut point Aus jedem erkannten Schnittpunkt eine Ablage mit Subclips erstellen
+ Create a clip marker at each detected cut point An jedem erkannten Schnittpunkt einen Clipmarker setzen
+ Sensitivity: Empfindlichkeit:
+ Normalize Mix Track to: Mix-Spur normalisieren auf:
+ Disabled clips Deaktivierte Clips
+ Empty tracks Leere Spuren
+ Gaps Lücken
+ Video effects Videoeffekte
+ Audio effects Audioeffekte
+ Text (graphics and captions) Text (Grafiken und Untertitel)
+ Clips Clips
+ Move clips to the lowest track possible Clips auf die niedrigstmögliche Spur verschieben
+ Keep: Behalten:
+ Video and Audio Video und Audio
+ Video Only Nur Video
+ Audio Only Nur Audio
+ Language: Sprache:
+ Audio on track {t} Audio auf Spur {t}
+ Audio analysis: Audioanalyse:
+ Recognize when different speakers are talking Erkennen, wenn verschiedene Personen sprechen
+ Template Name: Vorlagenname:
+ Comments: Kommentare:
+ (unavailable) (nicht verfügbar)
+ Decoders Decoder
+ Containers Container
+ Export formats Exportformate
+ Match {n} of {total} Treffer {n} von {total}
+ Saved template {path} Vorlage gespeichert: {path}
+ Scene Edit Detection: analysing in the background (see Progress) Szenenschnitterkennung: Analyse läuft im Hintergrund (siehe Fortschritt)
+ Delete Search Bin Suchablage löschen
+ (removed from {list}) (aus {list} entfernt)
+ {key} can't be used as a shortcut {key} kann nicht als Tastenkürzel verwendet werden
+ Keyboard Shortcuts Tastenkürzel
+ {active} (modified) {active} (geändert)
+ Loaded “{name}” „{name}“ geladen
+ My Shortcuts Meine Tastenkürzel
+ Deleted preset “{active}” Vorgabe „{active}“ gelöscht
+ Export… Exportieren…
+ Exported to {path} Exportiert nach {path}
+ Export: no file chosen (agents: shortcuts.export {path}) Exportieren: keine Datei gewählt (Agenten: shortcuts.export {path})
+ Imported “{name}” „{name}“ importiert
+ Import: no file chosen (agents: shortcuts.import {path}) Importieren: keine Datei gewählt (Agenten: shortcuts.import {path})
+ Keyboard: US (macOS) Tastatur: US (macOS)
+ Keyboard: US Tastatur: US
+ Save preset as: Vorgabe speichern als:
+ Commands: Befehle:
+ {panel} Panel Bedienfeld {panel}
+ Application shortcuts work whatever panel has focus Anwendungs-Tastenkürzel funktionieren unabhängig davon, welches Bedienfeld den Fokus hat
+ Panel shortcuts override application shortcuts while that panel has focus Bedienfeld-Tastenkürzel haben Vorrang vor Anwendungs-Tastenkürzeln, solange das Bedienfeld den Fokus hat
+ Modifier held / selected Zusatztaste gedrückt/ausgewählt
+ Search commands or keys Befehle oder Tasten suchen
+ Selected: {command} Ausgewählt: {command}
+ Command Befehl
+ Shortcut Tastenkürzel
+ Type a shortcut… (Esc cancels) Tastenkürzel drücken… (Esc bricht ab)
+ Add another shortcut Weiteres Tastenkürzel hinzufügen
+ No matching commands Keine passenden Befehle
+ Key: Taste:
+ Modifiers Zusatztasten
+ Nothing is assigned to this key Dieser Taste ist nichts zugewiesen
+ Click a key on the keyboard to see its shortcuts Klick auf eine Taste der Tastatur, um ihre Tastenkürzel zu sehen
+ Assign {key} to {command} {key} {command} zuweisen
+ Conflict: {key} is assigned to {commands} ({ctx}) Konflikt: {key} ist {commands} zugewiesen ({ctx})
+ and und
+ Click a command's Shortcut cell and press keys to assign it; + adds another shortcut. Klick in die Tastenkürzel-Zelle eines Befehls und drück die Tasten, um es zuzuweisen; + fügt ein weiteres Tastenkürzel hinzu.
+ Cleared {n} shortcut(s) of {command} {n} Tastenkürzel von {command} entfernt
+ No export preset named `{name}` Keine Exportvorgabe namens `{name}`
+ Open a sequence to export Öffne eine Sequenz, um sie zu exportieren
+ Destinations Ziele
+ Media File Mediendatei
+ Queue ({n}) Warteschlange ({n})
+ Send exports here with Send to Queue, then start the queue. Schick Exporte mit „An Warteschlange senden“ hierher und starte dann die Warteschlange.
+ Ready Bereit
+ Encoding {n}% Kodierung {n} %
+ Start Queue Warteschlange starten
+ Stop Stopp
+ Clear Finished Abgeschlossene entfernen
+ Not supported by FilmCraft's encoders yet Von den Encodern in FilmCraft noch nicht unterstützt
+ Sequence name Sequenzname
+ Folder Ordner
+ Preset Vorgabe
+ More presets… Weitere Vorgaben…
+ Multiplexer Multiplexer
+ The sequence has no caption track. Die Sequenz hat keine Untertitelspur.
+ Export Options Exportoptionen
+ Burn Captions Into Video Untertitel ins Video einbrennen
+ Create Sidecar File Begleitdatei erstellen
+ File Format Dateiformat
+ SubRip Subtitle (.srt) SubRip-Untertitel (.srt)
+ WebVTT (.vtt) WebVTT (.vtt)
+ Title Titel
+ Creator Urheber
+ Copyright Copyright
+ Image Bild
+ Frame Size Bildgröße
+ Match Source Wie Quelle
+ Field Order Halbbildreihenfolge
+ Aspect Seitenverhältnis
+ Profile Profil
+ Bitrate Encoding Bitratenkodierung
+ Target Bitrate Zielbitrate
+ Adaptive ({bpp} bits per pixel) Adaptiv ({bpp} Bit pro Pixel)
+ Maximum Bitrate Maximale Bitrate
+ Quality (CRF) Qualität (CRF)
+ Key Frame Distance Keyframe-Abstand
+ Quality Qualität
+ Render at Maximum Depth Mit maximaler Bittiefe rendern
+ Use Maximum Render Quality Maximale Renderqualität verwenden
+ Export Audio Audio exportieren
+ Audio Format Audioformat
+ Uncompressed (PCM) Unkomprimiert (PCM)
+ Match Source ({seq_sr} Hz) Wie Quelle ({seq_sr} Hz)
+ Channels Kanäle
+ Audio Bitrate Audiobitrate
+ Sample Size Samplegröße
+ 16 bit 16 Bit
+ 24 bit 24 Bit
+ 32 bit 32 Bit
+ 32 bit float 32 Bit Gleitkomma
+ FLAC stores whole-number samples only FLAC speichert nur ganzzahlige Samples
+ MXF export writes integer PCM only Der MXF-Export schreibt nur ganzzahliges PCM
+ Size / Opacity Größe/Deckkraft
+ Image Overlay Bildüberlagerung
+ PNG or JPEG file PNG- oder JPEG-Datei
+ Name Overlay Namensüberlagerung
+ Timecode Overlay Timecode-Überlagerung
+ Luma Min / Max Luma min./max.
+ Loudness Normalization Lautheitsnormalisierung
+ True Peak Limit True-Peak-Grenze
+ Audio only Nur Audio
+ Scaling Skalierung
+ Scale To Fit Einpassend skalieren
+ Scale To Fill Füllend skalieren
+ Stretch To Fill Füllend strecken
+ Summary Zusammenfassung
+ Sequence, {w}x{h}, {fps} fps, {rate} Hz Sequenz, {w}x{h}, {fps} fps, {rate} Hz
+ Estimated file size: {size} Geschätzte Dateigröße: {size}
+ Send to Queue An Warteschlange senden
+ Exporting {path} {path} wird exportiert
+ Added to the export queue Zur Exportwarteschlange hinzugefügt
+ Preset Manager Vorgabenmanager
+ Search presets Vorgaben suchen
+ Favorites only Nur Favoriten
+ Show in the Preset menu Im Vorgabenmenü anzeigen
+ User Benutzer
+ Save current settings as: Aktuelle Einstellungen speichern als:
+ Export presets Exportvorgaben
+ Import: no file chosen (agents: export.presets.import {path}) Importieren: keine Datei gewählt (Agenten: export.presets.import {path})
+ Export: no file chosen (agents: export.presets.export {path, names}) Exportieren: keine Datei gewählt (Agenten: export.presets.export {path, names})
+ Quick Export: open a sequence first Schnellexport: öffne zuerst eine Sequenz
+ File Name & Location Dateiname und Speicherort
+ Quick Export: {path} Schnellexport: {path}
+ Graphics problem: switched to software compositing Grafikproblem: auf Software-Compositing umgeschaltet
+ GPU acceleration is unavailable; preview renders on the CPU GPU-Beschleunigung ist nicht verfügbar; die Vorschau wird auf der CPU gerendert
+ Exporting Export läuft
+ Click to select, or click in empty space and drag to marquee select. Use Shift, Opt, and Cmd for other options. Klicken zum Auswählen oder in einen leeren Bereich klicken und ziehen für eine Rahmenauswahl. Umschalt, Wahl und Cmd bieten weitere Optionen.
+ Click to select all clips to the right in all tracks. Shift-click for a single track. Klicken wählt alle Clips rechts davon auf allen Spuren aus. Umschalt+Klick für eine einzelne Spur.
+ Click to select all clips to the left in all tracks. Shift-click for a single track. Klicken wählt alle Clips links davon auf allen Spuren aus. Umschalt+Klick für eine einzelne Spur.
+ Drag an edit point to ripple trim; later clips move to keep the gap closed. Zieh einen Schnittpunkt für Ripple-Trimmen; spätere Clips rücken nach, sodass keine Lücke entsteht.
+ Drag an edit point to roll it: the out of one clip and the in of the next move together. Zieh einen Schnittpunkt zum Rollen: Out des einen und In des nächsten Clips bewegen sich gemeinsam.
+ Drag an edge to change the clip's speed so it fills the new duration. Zieh eine Kante, um die Geschwindigkeit des Clips so zu ändern, dass er die neue Dauer füllt.
+ Drag the edge of a music clip to remix it to the new duration at musically matching beats. Zieh die Kante eines Musikclips, um ihn an musikalisch passenden Schlägen auf die neue Dauer zu remixen.
+ Click to split a clip. Shift-click to split all tracks. Klicken teilt einen Clip. Umschalt+Klick teilt alle Spuren.
+ Drag a clip to slip its source in/out without moving it. Zieh einen Clip, um sein Quell-In/-Out zu verschieben, ohne ihn zu bewegen (Slip).
+ Drag a clip to slide it between its neighbours. Zieh einen Clip, um ihn zwischen seinen Nachbarn zu verschieben (Slide).
+ Drag to scroll the timeline. Ziehen scrollt die Timeline.
+ Click to zoom in; Opt-click to zoom out. Klicken vergrößert; Wahl+Klick verkleinert.
+ FilmCraft hit an error In FilmCraft ist ein Fehler aufgetreten
+ Details: {path} Details: {path}
+ Opened {url} {url} geöffnet
+ (empty) (leer)
+ Step Back 1 Frame 1 Frame zurück
+ Step Forward 1 Frame 1 Frame vor
+ Match Playhead An Abspielposition angleichen
+ Gang to Program Mit Programm koppeln
+ AAC Audio AAC-Audio
+ AAC Audio 48 kHz 320 kbps AAC-Audio 48 kHz 320 kbit/s
+ MPEG-4 audio (.m4a), stereo 48 kHz AAC-LC at 320 kbps MPEG-4-Audio (.m4a), Stereo 48 kHz AAC-LC mit 320 kbit/s
+ AIFF AIFF
+ AIFF 48 kHz 16-bit AIFF 48 kHz 16 Bit
+ AIFF, stereo 48 kHz 16-bit PCM AIFF, Stereo 48 kHz 16-Bit-PCM
+ FLAC FLAC
+ FLAC 48 kHz 24-bit FLAC 48 kHz 24 Bit
+ FLAC, stereo 48 kHz 24-bit, lossless FLAC, Stereo 48 kHz 24 Bit, verlustfrei
+ FLAC (lossless) FLAC (verlustfrei)
+ Compression Level Kompressionsstufe
+ 0 fastest, 8 smallest 0 am schnellsten, 8 am kleinsten
+ APV APV
+ APV 422-10 APV 422-10
+ APV 422-12 APV 422-12
+ Anamorphic 2:1 (2.0) Anamorph 2:1 (2,0)
+ Animated GIF Animiertes GIF
+ Animated GIF 640×360 Animiertes GIF 640×360
+ Apple ProRes Apple ProRes
+ Apple ProRes 422 Apple ProRes 422
+ Apple ProRes 422 HQ Apple ProRes 422 HQ
+ Apple ProRes 422 LT Apple ProRes 422 LT
+ Apple ProRes 422 Proxy Apple ProRes 422 Proxy
+ Apple ProRes 4444 Apple ProRes 4444
+ Apple ProRes 4444 with Alpha Apple ProRes 4444 mit Alpha
+ Apple ProRes 4444 XQ Apple ProRes 4444 XQ
+ Application Anwendung
+ Apply Guide Template Hilfslinienvorlage anwenden
+ Auto Save Now Jetzt automatisch speichern
+ Auto-Match Loudness Lautheit automatisch angleichen
+ Avid DNxHR Avid DNxHR
+ Avid DNxHR HQ Avid DNxHR HQ
+ Avid DNxHR LB Avid DNxHR LB
+ Avid DNxHR SQ Avid DNxHR SQ
+ Avid-style OP-Atom: DNxHR HQ picture file plus one 24-bit 48 kHz PCM file per channel (_A1, _A2…) OP-Atom im Avid-Stil: DNxHR-HQ-Bilddatei plus eine PCM-Datei mit 24 Bit und 48 kHz pro Kanal (_A1, _A2…)
+ BMP BMP
+ BMP Sequence BMP-Sequenz
+ Baseline Baseline
+ Begin Text Editing for a Graphic Layer Textbearbeitung für eine Grafikebene beginnen
+ Begins With Beginnt mit
+ Blur In Weich einblenden
+ Blur Out Weich ausblenden
+ Brightens inside a feathered circular mask Hellt das Innere einer weichen kreisförmigen Maske auf
+ Broadcast Broadcast
+ CBR CBR
+ Cancel Dynamic Trim Dynamisches Trimmen abbrechen
+ Cancel Queued Export Export in Warteschlange abbrechen
+ Center Left Mitte links
+ Center Right Mitte rechts
+ Center align text Text zentrieren
+ Change Mask Maske ändern
+ Clear All Events Alle Ereignisse löschen
+ Clear Edit Point Selection Auswahl der Schnittpunkte aufheben
+ Clear Finished Exports Abgeschlossene Exporte entfernen
+ Clear Poster Frame Posterframe entfernen
+ Close Bin Ablage schließen
+ Close Sequence Sequenz schließen
+ Contains Enthält
+ Cut to Camera 1 Auf Kamera 1 schneiden
+ Cut to Camera 2 Auf Kamera 2 schneiden
+ Cut to Camera 3 Auf Kamera 3 schneiden
+ Cut to Camera 4 Auf Kamera 4 schneiden
+ Cut to Camera 5 Auf Kamera 5 schneiden
+ Cut to Camera 6 Auf Kamera 6 schneiden
+ Cut to Camera 7 Auf Kamera 7 schneiden
+ Cut to Camera 8 Auf Kamera 8 schneiden
+ Cut to Camera 9 Auf Kamera 9 schneiden
+ D1/DV NTSC (0.9091) D1/DV NTSC (0,9091)
+ D1/DV PAL (1.0940) D1/DV PAL (1,0940)
+ DVCPRO HD (1.5) DVCPRO HD (1,5)
+ Darkens outside a feathered oval mask Dunkelt den Bereich außerhalb einer weichen ovalen Maske ab
+ Decrease Audio Tracks Height Höhe der Audiospuren verringern
+ Decrease Clip Volume Cliplautstärke verringern
+ Decrease Clip Volume Many Cliplautstärke stark verringern
+ Decrease Font Size by Five Units Schriftgröße um fünf Einheiten verkleinern
+ Decrease Font Size by One Unit Schriftgröße um eine Einheit verkleinern
+ Decrease Leading by Five Units Zeilenabstand um fünf Einheiten verringern
+ Decrease Leading by One Unit Zeilenabstand um eine Einheit verringern
+ Decrease Video Tracks Height Höhe der Videospuren verringern
+ Delete Captions Untertitel löschen
+ Delete Graphic Layer Grafikebene löschen
+ Delete Guide Template Hilfslinienvorlage löschen
+ Delete Media Cache Files Mediencache-Dateien löschen
+ Discard Unsaved Changes Nicht gespeicherte Änderungen verwerfen
+ Does Not Contain Enthält nicht
+ Download Speech Model Sprachmodell herunterladen
+ Dynamic Trim Stop Dynamisches Trimmen stoppen
+ Edit Caption Text Untertiteltext bearbeiten
+ Ellipse Tool Ellipsenwerkzeug
+ Ends With Endet mit
+ Entire Source Gesamte Quelle
+ EssentialSound Essential Sound
+ Export Frame Frame exportieren
+ Extend Next Edit To Playhead Nächsten Schnitt bis zur Abspielposition erweitern
+ Extend Previous Edit To Playhead Vorherigen Schnitt bis zur Abspielposition erweitern
+ Extend Selected Edit to Playhead Ausgewählten Schnitt bis zur Abspielposition erweitern
+ Extend Selection Down Auswahl nach unten erweitern
+ Extend Selection Left Auswahl nach links erweitern
+ Extend Selection Right Auswahl nach rechts erweitern
+ Extend Selection Up Auswahl nach oben erweitern
+ Fade In Einblenden
+ Gaussian Blur from 0 to 60 over the last second Gaußscher Weichzeichner von 0 bis 60 in der letzten Sekunde
+ Gaussian Blur from 60 to 0 over the first second Gaußscher Weichzeichner von 60 bis 0 in der ersten Sekunde
+ Generate Ducking Keyframes Ducking-Keyframes erzeugen
+ Go to Next Edit Point Zum nächsten Schnittpunkt gehen
+ Go to Next Edit Point on Any Track Zum nächsten Schnittpunkt auf einer beliebigen Spur gehen
+ Go to Previous Edit Point Zum vorherigen Schnittpunkt gehen
+ Go to Previous Edit Point on Any Track Zum vorherigen Schnittpunkt auf einer beliebigen Spur gehen
+ Go to Selected Clip End Zum Ende des ausgewählten Clips gehen
+ Go to Selected Clip Start Zum Anfang des ausgewählten Clips gehen
+ Go to Sequence End Zum Sequenzende gehen
+ Go to Sequence Start Zum Sequenzanfang gehen
+ H.264 H.264
+ AV1 AV1
+ H.264 1920×1080 for video sharing sites, VBR 1 pass, 16 Mbps H.264 1920×1080 für Videoportale, VBR 1 Durchgang, 16 Mbit/s
+ H.264 1920×1080, VBR 1 pass, 20 Mbps target, AAC 320 kbps H.264 1920×1080, VBR 1 Durchgang, Ziel 20 Mbit/s, AAC 320 kbit/s
+ H.264 1920×1080, VBR 2 pass, 18 Mbps H.264 1920×1080, VBR 2 Durchgänge, 18 Mbit/s
+ H.264 3840×2160 for video sharing sites, VBR 1 pass, 45 Mbps H.264 3840×2160 für Videoportale, VBR 1 Durchgang, 45 Mbit/s
+ H.264 3840×2160, VBR 1 pass, 60 Mbps target, AAC 320 kbps H.264 3840×2160, VBR 1 Durchgang, Ziel 60 Mbit/s, AAC 320 kbit/s
+ H.264 3840×2160, VBR 2 pass, 50 Mbps H.264 3840×2160, VBR 2 Durchgänge, 50 Mbit/s
+ H.264 9:16 portrait for short-form social video, scaled to fill, 12 Mbps H.264 9:16 hochkant für kurze Social-Media-Videos, füllend skaliert, 12 Mbit/s
+ H.264 at the sequence's frame size and rate; 0.05 bits per pixel H.264 mit Bildgröße und Framerate der Sequenz; 0,05 Bit pro Pixel
+ H.264 at the sequence's frame size and rate; 0.1 bits per pixel H.264 mit Bildgröße und Framerate der Sequenz; 0,1 Bit pro Pixel
+ H.264 at the sequence's frame size and rate; bitrate adapts to the frame size (0.2 bits per pixel) H.264 mit Bildgröße und Framerate der Sequenz; die Bitrate passt sich der Bildgröße an (0,2 Bit pro Pixel)
+ HD Anamorphic 1080 (1.333) HD anamorph 1080 (1,333)
+ Hand Tool Handwerkzeug
+ High Quality 1080p HD Hohe Qualität 1080p HD
+ High Quality 2160p 4K Hohe Qualität 2160p 4K
+ Image Sequence Bildsequenz
+ Increase Audio Tracks Height Höhe der Audiospuren vergrößern
+ Increase Clip Volume Cliplautstärke erhöhen
+ Increase Clip Volume Many Cliplautstärke stark erhöhen
+ Increase Font Size by Five Units Schriftgröße um fünf Einheiten vergrößern
+ Increase Font Size by One Unit Schriftgröße um eine Einheit vergrößern
+ Increase Leading by Five Units Zeilenabstand um fünf Einheiten vergrößern
+ Increase Leading by One Unit Zeilenabstand um eine Einheit vergrößern
+ Increase Video Tracks Height Höhe der Videospuren vergrößern
+ Large blocks resolving to the picture over the first second Große Blöcke, die sich in der ersten Sekunde zum Bild auflösen
+ Left align text Text linksbündig
+ Looping GIF, 640×360 at 15 fps GIF in Schleife, 640×360 mit 15 fps
+ Lower First Unteres Halbbild zuerst
+ Lumetri Lumetri
+ MXF OP-Atom MXF OP-Atom
+ MXF OP-Atom DNxHR (Avid) MXF OP-Atom DNxHR (Avid)
+ MXF OP1a MXF OP1a
+ MXF OP1a DNxHR HQ MXF OP1a DNxHR HQ
+ MXF OP1a H.264 MXF OP1a H.264
+ MXF OP1a ProRes 422 HQ MXF OP1a ProRes 422 HQ
+ MXF OP1a, DNxHR HQ (8-bit 4:2:2), 24-bit 48 kHz PCM, start timecode MXF OP1a, DNxHR HQ (8 Bit 4:2:2), PCM 24 Bit 48 kHz, Start-Timecode
+ MXF OP1a, H.264 High long GOP (0.3 bits per pixel), 24-bit 48 kHz PCM MXF OP1a, H.264 High Long-GOP (0,3 Bit pro Pixel), PCM 24 Bit 48 kHz
+ MXF OP1a, ProRes 422 HQ, 24-bit 48 kHz PCM, start timecode MXF OP1a, ProRes 422 HQ, PCM 24 Bit 48 kHz, Start-Timecode
+ Main Main
+ Mark In (Hover Scrub) In-Punkt setzen (Hover-Scrubbing)
+ Mark Out (Hover Scrub) Out-Punkt setzen (Hover-Scrubbing)
+ Masks Masken
+ Match Source – Adaptive High Bitrate Wie Quelle – adaptive hohe Bitrate
+ Match Source – Adaptive Low Bitrate Wie Quelle – adaptive niedrige Bitrate
+ Match Source – Adaptive Medium Bitrate Wie Quelle – adaptive mittlere Bitrate
+ Matches Entspricht
+ Maximize or Restore Active Frame Aktiven Rahmen maximieren oder wiederherstellen
+ Maximize or Restore Frame Under Cursor Rahmen unter dem Cursor maximieren oder wiederherstellen
+ Media Browser Settings Medienbrowser-Einstellungen
+ MediaBrowser Medienbrowser
+ MediaCache Mediencache
+ Merge Captions Untertitel zusammenführen
+ Mixer Mischpult
+ Mosaic In Mosaik-Einblendung
+ Move All Audio Targets Down Alle Audioziele nach unten verschieben
+ Move All Audio Targets Up Alle Audioziele nach oben verschieben
+ Move All Video Targets Down Alle Videoziele nach unten verschieben
+ Move All Video Targets Up Alle Videoziele nach oben verschieben
+ Move Selection Down Auswahl nach unten bewegen
+ Move Selection End Auswahl ans Ende bewegen
+ Move Selection Home Auswahl an den Anfang bewegen
+ Move Selection Left Auswahl nach links bewegen
+ Move Selection Page Down Auswahl eine Seite nach unten bewegen
+ Move Selection Page Up Auswahl eine Seite nach oben bewegen
+ Move Selection Right Auswahl nach rechts bewegen
+ Move Selection Up Auswahl nach oben bewegen
+ Multi-Camera Record On/Off Toggle Mehrkamera-Aufnahme ein/aus
+ Multicam Mehrkamera
+ Navigate to End of Segment Zum Segmentende gehen
+ Navigate to Next Line Zur nächsten Zeile gehen
+ Navigate to Next Word Zum nächsten Wort gehen
+ Navigate to Previous Line Zur vorherigen Zeile gehen
+ Navigate to Previous Word Zum vorherigen Wort gehen
+ Navigate to Start of Segment Zum Segmentanfang gehen
+ Navigation Navigation
+ Next Multi-Camera Page Nächste Mehrkamera-Seite
+ Nudge Clip Selection Down Clipauswahl nach unten versetzen
+ Nudge Clip Selection Left Five Frames Clipauswahl um fünf Frames nach links versetzen
+ Nudge Clip Selection Left One Frame Clipauswahl um einen Frame nach links versetzen
+ Nudge Clip Selection Right Five Frames Clipauswahl um fünf Frames nach rechts versetzen
+ Nudge Clip Selection Right One Frame Clipauswahl um einen Frame nach rechts versetzen
+ Nudge Clip Selection Up Clipauswahl nach oben versetzen
+ Nudge Selected Object down by five Ausgewähltes Objekt um fünf nach unten versetzen
+ Nudge Selected Object down by one Ausgewähltes Objekt um eins nach unten versetzen
+ Nudge Selected Object to left by five Ausgewähltes Objekt um fünf nach links versetzen
+ Nudge Selected Object to left by one Ausgewähltes Objekt um eins nach links versetzen
+ Nudge Selected Object to right by five Ausgewähltes Objekt um fünf nach rechts versetzen
+ Nudge Selected Object to right by one Ausgewähltes Objekt um eins nach rechts versetzen
+ Nudge Selected Object up by five Ausgewähltes Objekt um fünf nach oben versetzen
+ Nudge Selected Object up by one Ausgewähltes Objekt um eins nach oben versetzen
+ Nudge Volume +1dB Lautstärke +1 dB
+ Nudge Volume +3dB Lautstärke +3 dB
+ Nudge Volume -1dB Lautstärke −1 dB
+ Nudge Volume -3dB Lautstärke −3 dB
+ Numbered BMP stills (24-bit) Nummerierte BMP-Standbilder (24 Bit)
+ JPEG JPEG
+ Targa Targa
+ DPX DPX
+ JPEG Sequence JPEG-Sequenz
+ Targa Sequence Targa-Sequenz
+ DPX Sequence DPX-Sequenz
+ Numbered JPEG stills (quality 90) Nummerierte JPEG-Standbilder (Qualität 90)
+ Numbered Targa stills (24-bit, uncompressed) Nummerierte Targa-Standbilder (24 Bit, unkomprimiert)
+ Numbered DPX stills (10-bit RGB) Nummerierte DPX-Standbilder (10 Bit RGB)
+ OpenEXR OpenEXR
+ OpenEXR Sequence OpenEXR-Sequenz
+ Numbered OpenEXR stills (half float, linear, uncompressed) Nummerierte OpenEXR-Standbilder (Half Float, linear, unkomprimiert)
+ Numbered PNG stills at the sequence's frame size Nummerierte PNG-Standbilder in der Bildgröße der Sequenz
+ Numbered TIFF stills (RGB, 8-bit) Nummerierte TIFF-Standbilder (RGB, 8 Bit)
+ Opacity 0 → 100 % over the first second Deckkraft 0 → 100 % in der ersten Sekunde
+ Opacity 100 → 0 % over the last second Deckkraft 100 → 0 % in der letzten Sekunde
+ Open Bin Ablage öffnen
+ Open Search Suche öffnen
+ PNG PNG
+ PNG Sequence PNG-Sequenz
+ Panel Bedienfeld
+ Pen Tool Zeichenstift-Werkzeug
+ PiP 35% Upper Right Bild-im-Bild 35 % oben rechts
+ Picture-in-picture: 35 % scale in the upper right Bild-im-Bild: 35 % Skalierung oben rechts
+ Play Around Um Position herum abspielen
+ Play In to Out with Preroll/Postroll Von In bis Out mit Vor- und Nachlauf abspielen
+ Play from Playhead to Out Point Von der Abspielposition bis zum Out-Punkt abspielen
+ Play/Stop Wiedergabe/Stopp
+ Previous Multi-Camera Page Vorherige Mehrkamera-Seite
+ Progressive Progressiv
+ ProjectPanel Projekt-Bedienfeld
+ QuickTime (Motion JPEG) QuickTime (Motion JPEG)
+ QuickTime, APV 422-10 (10-bit 4:2:2), 24-bit 48 kHz PCM QuickTime, APV 422-10 (10 Bit 4:2:2), PCM 24 Bit 48 kHz
+ QuickTime, APV 422-12 (12-bit 4:2:2), 24-bit 48 kHz PCM QuickTime, APV 422-12 (12 Bit 4:2:2), PCM 24 Bit 48 kHz
+ QuickTime, DNxHR HQ (8-bit 4:2:2), 24-bit 48 kHz PCM QuickTime, DNxHR HQ (8 Bit 4:2:2), PCM 24 Bit 48 kHz
+ QuickTime, DNxHR LB (8-bit 4:2:2), 24-bit 48 kHz PCM QuickTime, DNxHR LB (8 Bit 4:2:2), PCM 24 Bit 48 kHz
+ QuickTime, DNxHR SQ (8-bit 4:2:2), 24-bit 48 kHz PCM QuickTime, DNxHR SQ (8 Bit 4:2:2), PCM 24 Bit 48 kHz
+ QuickTime, ProRes 422 HQ, 24-bit 48 kHz PCM QuickTime, ProRes 422 HQ, PCM 24 Bit 48 kHz
+ QuickTime, ProRes 422 LT, 24-bit 48 kHz PCM QuickTime, ProRes 422 LT, PCM 24 Bit 48 kHz
+ QuickTime, ProRes 422 Proxy, 24-bit 48 kHz PCM QuickTime, ProRes 422 Proxy, PCM 24 Bit 48 kHz
+ QuickTime, ProRes 4444 (4:4:4), 24-bit 48 kHz PCM QuickTime, ProRes 4444 (4:4:4), PCM 24 Bit 48 kHz
+ QuickTime, ProRes 4444 (4:4:4) with alpha channel, 24-bit 48 kHz PCM QuickTime, ProRes 4444 (4:4:4) mit Alphakanal, PCM 24 Bit 48 kHz
+ QuickTime, ProRes 4444 XQ (4:4:4), 24-bit 48 kHz PCM QuickTime, ProRes 4444 XQ (4:4:4), PCM 24 Bit 48 kHz
+ QuickTime, ProRes 422, 24-bit 48 kHz PCM QuickTime, ProRes 422, PCM 24 Bit 48 kHz
+ Rate Stretch Tool Ratendehnungswerkzeug
+ Razor Tool Rasierklingen-Werkzeug
+ Rectangle Tool Rechteckwerkzeug
+ Remix Tool Remix-Werkzeug
+ Right align text Text rechtsbündig
+ Ripple Edit Tool Ripple-Werkzeug
+ Ripple Trim Next Edit to Playhead Nächsten Schnitt per Ripple bis zur Abspielposition trimmen
+ Ripple Trim Previous Edit to Playhead Vorherigen Schnitt per Ripple bis zur Abspielposition trimmen
+ Rolling Edit Tool Rollen-Werkzeug
+ Select Camera 1 Kamera 1 auswählen
+ Select Camera 2 Kamera 2 auswählen
+ Select Camera 3 Kamera 3 auswählen
+ Select Camera 4 Kamera 4 auswählen
+ Select Camera 5 Kamera 5 auswählen
+ Select Camera 6 Kamera 6 auswählen
+ Select Camera 7 Kamera 7 auswählen
+ Select Camera 8 Kamera 8 auswählen
+ Select Camera 9 Kamera 9 auswählen
+ Select Clip at Playhead Clip an der Abspielposition auswählen
+ Select Find Box Suchfeld auswählen
+ Select Next Clip Nächsten Clip auswählen
+ Select Next Panel Nächstes Bedienfeld auswählen
+ Select Previous Clip Vorherigen Clip auswählen
+ Select Previous Panel Vorheriges Bedienfeld auswählen
+ Select to Next Line Bis zur nächsten Zeile auswählen
+ Select to Next Word Bis zum nächsten Wort auswählen
+ Select to Previous Line Bis zur vorherigen Zeile auswählen
+ Select to Previous Word Bis zum vorherigen Wort auswählen
+ Select to Segment End Bis zum Segmentende auswählen
+ Select to Segment Start Bis zum Segmentanfang auswählen
+ Selection Tool Auswahlwerkzeug
+ Set Comparison Reference Vergleichsreferenz festlegen
+ Set Creative Look Kreativen Look festlegen
+ Set Input LUT Eingabe-LUT festlegen
+ Set Project Panel View Ansicht des Projekt-Bedienfelds festlegen
+ Show Next Screen Nächsten Bildschirm anzeigen
+ Show Previous Screen Vorherigen Bildschirm anzeigen
+ Show Program Transcript Programmtranskript anzeigen
+ Shuttle Left Shuttle links
+ Shuttle Right Shuttle rechts
+ Shuttle Slow Left Shuttle langsam links
+ Shuttle Slow Right Shuttle langsam rechts
+ Shuttle Stop Shuttle stopp
+ Slide Clip Selection Left Five Frames Clipauswahl um fünf Frames nach links verschieben (Slide)
+ Slide Clip Selection Left One Frame Clipauswahl um einen Frame nach links verschieben (Slide)
+ Slide Clip Selection Right Five Frames Clipauswahl um fünf Frames nach rechts verschieben (Slide)
+ Slide Clip Selection Right One Frame Clipauswahl um einen Frame nach rechts verschieben (Slide)
+ Slide Tool Slide-Werkzeug
+ Slip Clip Selection Left Five Frames Inhalt der Clipauswahl um fünf Frames nach links verschieben (Slip)
+ Slip Clip Selection Left One Frame Inhalt der Clipauswahl um einen Frame nach links verschieben (Slip)
+ Slip Clip Selection Right Five Frames Inhalt der Clipauswahl um fünf Frames nach rechts verschieben (Slip)
+ Slip Clip Selection Right One Frame Inhalt der Clipauswahl um einen Frame nach rechts verschieben (Slip)
+ Slip Tool Slip-Werkzeug
+ Social Vertical 1080×1920 Social Media hochkant 1080×1920
+ Soft Vignette Weiche Vignette
+ Source In/Out Quell-In/-Out
+ Split Caption Untertitel teilen
+ Square Pixels (1.0) Quadratische Pixel (1,0)
+ Stack Clips Clips stapeln
+ Start Export Queue Exportwarteschlange starten
+ Start Voice-over Recording Voice-over-Aufnahme starten
+ Step Back Five Frames Fünf Frames zurück
+ Step Back One Frame Einen Frame zurück
+ Step Forward Five Frames Fünf Frames vor
+ Step Forward One Frame Einen Frame vor
+ Stop Export Queue Exportwarteschlange stoppen
+ Stop Multi-Camera Recording Mehrkamera-Aufnahme stoppen
+ Stop Voice-over Recording Voice-over-Aufnahme stoppen
+ Sync Voice-over Capture Voice-over-Aufnahme synchronisieren
+ TIFF TIFF
+ TIFF Sequence TIFF-Sequenz
+ TextPanel Text-Bedienfeld
+ Thumbnail Size Next Nächste Miniaturgröße
+ Thumbnail Size Previous Vorherige Miniaturgröße
+ Toggle All Audio Targets Alle Audioziele ein/aus
+ Toggle All Source Audio Gesamtes Quellaudio ein/aus
+ Toggle All Source Video Gesamtes Quellvideo ein/aus
+ Toggle All Video Targets Alle Videoziele ein/aus
+ Toggle Audio During Scrubbing Audio beim Scrubben ein/aus
+ Toggle Full Screen Vollbild ein/aus
+ Toggle Mute for All Targeted Audio Tracks Stummschaltung für alle Ziel-Audiospuren ein/aus
+ Toggle Solo for All Targeted Audio Tracks Solo für alle Ziel-Audiospuren ein/aus
+ Toggle Source/Program Monitor Focus Fokus zwischen Quell- und Programmmonitor wechseln
+ Toggle Target Audio 1 Audioziel 1 ein/aus
+ Toggle Target Audio 2 Audioziel 2 ein/aus
+ Toggle Target Audio 3 Audioziel 3 ein/aus
+ Toggle Target Audio 4 Audioziel 4 ein/aus
+ Toggle Target Audio 5 Audioziel 5 ein/aus
+ Toggle Target Audio 6 Audioziel 6 ein/aus
+ Toggle Target Audio 7 Audioziel 7 ein/aus
+ Toggle Target Audio 8 Audioziel 8 ein/aus
+ Toggle Target Video 1 Videoziel 1 ein/aus
+ Toggle Target Video 2 Videoziel 2 ein/aus
+ Toggle Target Video 3 Videoziel 3 ein/aus
+ Toggle Target Video 4 Videoziel 4 ein/aus
+ Toggle Target Video 5 Videoziel 5 ein/aus
+ Toggle Target Video 6 Videoziel 6 ein/aus
+ Toggle Target Video 7 Videoziel 7 ein/aus
+ Toggle Target Video 8 Videoziel 8 ein/aus
+ Toggle Track Output for All Targeted Video Tracks Spurausgabe für alle Ziel-Videospuren ein/aus
+ Toggle Trim Type Trimmart wechseln
+ Toggle View Ansicht wechseln
+ Track Select Backward Tool Werkzeug „Spur rückwärts auswählen“
+ Track Select Forward Tool Werkzeug „Spur vorwärts auswählen“
+ Track Selected Mask Ausgewählte Maske verfolgen
+ Trim Next Edit to Playhead Nächsten Schnitt bis zur Abspielposition trimmen
+ Trim Previous Edit to Playhead Vorherigen Schnitt bis zur Abspielposition trimmen
+ Trimming Trimmen
+ Type Tool Textwerkzeug
+ Unstack Clips Clipstapel auflösen
+ Upper First Oberes Halbbild zuerst
+ VBR, 1 pass VBR, 1 Durchgang
+ VBR, 2 pass VBR, 2 Durchgänge
+ CRF (constant quality) CRF (konstante Qualität)
+ Vimeo 1080p Full HD Vimeo 1080p Full HD
+ Vimeo 2160p 4K Ultra HD Vimeo 2160p 4K Ultra HD
+ Voice-over Record Voice-over-Aufnahme
+ Voiceover Voice-over
+ WAV, stereo 48 kHz 16-bit PCM WAV, Stereo 48 kHz 16-Bit-PCM
+ WAV, stereo 48 kHz 24-bit PCM WAV, Stereo 48 kHz 24-Bit-PCM
+ Warm Tint Warme Tönung
+ Warm highlights, brown shadows Warme Lichter, braune Tiefen
+ Waveform Audio Waveform Audio
+ Waveform Audio 48 kHz 16-bit Waveform Audio 48 kHz 16 Bit
+ Waveform Audio 48 kHz 24-bit Waveform Audio 48 kHz 24 Bit
+ Web & Social Web und Social Media
+ Work Area Arbeitsbereichsleiste
+ Write Automation Automation schreiben
+ YouTube 1080p Full HD YouTube 1080p Full HD
+ YouTube 2160p 4K Ultra HD YouTube 2160p 4K Ultra HD
+ Zoom Program Monitor to 100% Programmmonitor auf 100 % zoomen
+ Zoom Program Monitor to Fit Programmmonitor einpassen
+ Zoom Source Monitor to 100% Quellmonitor auf 100 % zoomen
+ Zoom Source Monitor to Fit Quellmonitor einpassen
+ Zoom Tool Zoomwerkzeug
+ with: durch:
+ Interface Language Sprache der Oberfläche
+ System Language Systemsprache
+ Cinematic Filmisch
+ Film Emulation Filmemulation
+ Technical Technisch
+ Teal Shadows, Warm Skin Petrolfarbene Tiefen, warme Haut
+ Night Exterior Nacht außen
+ Golden Dusk Goldene Dämmerung
+ Steel Blue Stahlblau
+ Hard Sun Harte Sonne
+ Faded Print Verblasste Kopie
+ Silver Retention Silberrückhalt
+ Cross Processed Crossentwicklung
+ Warm Negative Warmes Negativ
+ Neutral Mono Neutrales Mono
+ Hard Mono Hartes Mono
+ Sepia Tone Sepiaton
+ Cold Mono Kaltes Mono
+ Lift Shadows Tiefen anheben
+ Protect Highlights Lichter schützen
+ Half Saturation Halbe Sättigung
+ Boost Vibrance Dynamik erhöhen
+ Legal Range Squeeze Auf legalen Bereich stauchen
+ A boxed label with a round pointer; move the label and the pointer follows. Ein Etikett im Kasten mit rundem Zeiger; verschiebst du das Etikett, folgt der Zeiger.
+ A rounded tag that fits its text, with a status dot. Ein abgerundetes Tag, das sich an seinen Text anpasst, mit Statuspunkt.
+ A title on a rounded card with a soft shadow. Ein Titel auf einer abgerundeten Karte mit weichem Schatten.
+ Accent Color Akzentfarbe
+ Bar Color Balkenfarbe
+ Box Color Kastenfarbe
+ Box Opacity Kastendeckkraft
+ Callout – Pointer Callout – Zeiger
+ Callout – Tag Callout – Tag
+ Callouts Callouts
+ Credits Abspann
+ Dot Color Punktfarbe
+ Heading Überschrift
+ Large centred title, accent rule and subtitle. Großer zentrierter Titel, Akzentlinie und Untertitel.
+ Lower Third – Rule Bauchbinde – Linie
+ Lower Third – Slab Bauchbinde – Fläche
+ Lower Thirds Bauchbinden
+ Name Color Namensfarbe
+ Name Size Namensgröße
+ Name and role on a coloured slab that widens with the name. Name und Funktion auf einer farbigen Fläche, die mit dem Namen breiter wird.
+ Name over a thin rule that always matches the name's width. Name über einer dünnen Linie, die immer so breit ist wie der Name.
+ Pointer Color Zeigerfarbe
+ Role Funktion
+ Rule Color Linienfarbe
+ Show Dot Punkt anzeigen
+ Show Role Funktion anzeigen
+ Slab Color Flächenfarbe
+ Tag Color Tag-Farbe
+ Title Color Titelfarbe
+ Title Size Titelgröße
+ Title – Boxed Titel – im Kasten
+ Title – Centered Titel – zentriert
+ Titles Titel
+ Select an item to preview it Wähle ein Element aus, um eine Vorschau zu sehen
+ End Credits Abspann
+ End Credits – Roll Abspann – Rolltitel
+ Ticker – Crawl Laufband – Laufschrift
+ Centred credits that roll up from below the frame and leave at the top. Zentrierter Abspann, der von unterhalb des Bildes nach oben rollt und oben verschwindet.
+ A news-style line that crawls in from the right and leaves at the left. Eine Zeile im Nachrichtenstil, die von rechts hereinläuft und links verschwindet.
+ out Out
+ in In
+ The language changed but could not be saved: {e} Die Sprache wurde geändert, konnte aber nicht gespeichert werden: {e}
+ no Chinese font is installed on this system; the interface stays in English auf diesem System ist keine chinesische Schrift installiert; die Oberfläche bleibt auf Englisch
+ no Korean font is installed on this system; the interface stays in English Auf diesem System ist keine koreanische Schrift installiert; die Oberfläche bleibt auf Englisch
+ no Japanese font is installed on this system; the interface stays in English auf diesem System ist keine japanische Schrift installiert; die Oberfläche bleibt auf Englisch
+ Show Anzeigen
+ Sort Sortieren
+ Reverse the order Reihenfolge umkehren
+ Grab bag Allerlei
+ Table Tabelle
+ No contributor data was built into this copy. In diese Kopie wurden keine Daten zu Mitwirkenden eingebaut.
+ No model credits were built into this copy. In diese Kopie wurden keine Modell-Credits eingebaut.
+ Company Firma
+ Model Modell
+ Version Version
+ Commits Commits
+ % of all commits % aller Commits
+ Lines +/− Zeilen +/−
+ Audio output failed: playing without sound (check Settings ▸ Audio Hardware) Audioausgabe fehlgeschlagen: Wiedergabe ohne Ton (prüfe Voreinstellungen ▸ Audiohardware)
+ Audio output is not responding: playing without sound (check Settings ▸ Audio Hardware) Audioausgabe reagiert nicht: Wiedergabe ohne Ton (prüfe Voreinstellungen ▸ Audiohardware)
+ Clip Speed / Duration Clipgeschwindigkeit/-dauer
+ Speed: Geschwindigkeit:
+ Reverse Speed Rückwärts abspielen
+ Ripple Edit, Shifting Trailing Clips Ripple-Bearbeitung, nachfolgende Clips verschieben
+ About Über
+ Contributors Mitwirkende
+ Models Modelle
+ Main (8-bit) Main (8 Bit)
+ Main 10 (10-bit, HDR) Main 10 (10 Bit, HDR)
+ Main (8-bit; Main 10 for HDR sequences) Main (8 Bit; Main 10 für HDR-Sequenzen)
+ Encoder Encoder
+ Hardware (H.265 has no software encoder) Hardware (für H.265 gibt es keinen Software-Encoder)
+ Hardware (AV1 has no software encoder) Hardware (für AV1 gibt es keinen Software-Encoder)
+ Text Properties Texteigenschaften
+ Text Box Height Textfeldhöhe
+ Paragraph Text Absatztext
+ Point Text Punkttext
+ Text Layer Type Art der Textebene
+ Text Styling Textgestaltung
+ New Color Matte Neue Farbfläche
+ Color Matte Color Farbe der Farbfläche
+ Color: Farbe:
+ · {time} left · noch {time}
+ Discard take Take verwerfen
+ Voice-over take discarded Voice-over-Take verworfen
+ Binary assets added Hinzugefügte Binärdateien
+ Binary assets removed Entfernte Binärdateien
+ Deselect All Project Items Auswahl aller Projektelemente aufheben
+ Display name Anzeigename
+ First commit Erster Commit
+ H.265 (HEVC) H.265 (HEVC)
+ Last commit Letzter Commit
+ Line delta Zeilendifferenz
+ Lines added Hinzugefügte Zeilen
+ Lines deleted Gelöschte Zeilen
+ Merged PRs Gemergte PRs
+ Name (A–Z) Name (A–Z)
+ Real name Echter Name
+ Select All Project Items Alle Projektelemente auswählen
+ Username Benutzername
+ Vertical Type Tool Vertikales Textwerkzeug
+ Go to previous keyframe Zum vorherigen Keyframe gehen
+ Go to next keyframe Zum nächsten Keyframe gehen
+ Add keyframe Keyframe hinzufügen
+ Remove keyframe Keyframe entfernen
+ Turn on animation and add keyframe Animation einschalten und Keyframe hinzufügen
+ Click to select, or click in empty space and drag to marquee select. Use Shift, Alt, and Ctrl for other options. Klicken zum Auswählen oder in einen leeren Bereich klicken und ziehen für eine Rahmenauswahl. Umschalt, Alt und Strg bieten weitere Optionen.
+ Click to zoom in; Alt-click to zoom out. Klicken vergrößert; Alt+Klick verkleinert.
+ Drag: move · Alt-click: smooth/corner · Ctrl-click: delete Ziehen: verschieben · Alt+Klick: glatt/Ecke · Strg+Klick: löschen
+ Drag inward to round the corners Nach innen ziehen, um die Ecken abzurunden
+ Include Alpha Channel Alphakanal einschließen
+ Sequence Settings Sequenzeinstellungen
+ Color Management Farbmanagement
+ VR Properties VR-Eigenschaften
+ Editing Mode: Bearbeitungsmodus:
+ Timebase: Zeitbasis:
+ Frame Size: Bildgröße:
+ Pixel Aspect Ratio: Pixel-Seitenverhältnis:
+ Fields: Halbbilder:
+ Channel Format: Kanalformat:
+ Number of Channels: Anzahl der Kanäle:
+ Preview File Format: Format der Vorschaudateien:
+ Working Color Space: Arbeitsfarbraum:
+ Projection: Projektion:
+ Layout: Layout:
+ Captured View: Aufgenommene Ansicht:
+ Video Previews Videovorschauen
+ No Fields (Progressive Scan) Keine Halbbilder (progressiv)
+ Custom ({ratio}) Benutzerdefiniert ({ratio})
+ {rate} frames/second {rate} Frames/Sekunde
+ {rate} fps Drop-Frame Timecode {rate} fps Drop-Frame-Timecode
+ {rate} fps Non Drop-Frame Timecode {rate} fps Non-Drop-Frame-Timecode
+ {rate} fps Timecode {rate} fps Timecode
+ horizontal horizontal
+ vertical vertikal
+ Scale motion effects proportionally when changing frame size Bewegungseffekte beim Ändern der Bildgröße proportional skalieren
+ Maximum Bit Depth Maximale Bittiefe
+ Maximum Render Quality Maximale Renderqualität
+ Composite in Linear Color In linearem Farbraum zusammensetzen
+ Auto Tone Map Media (HDR and log into SDR) Automatisches Tone-Mapping für Medien (HDR und Log nach SDR)
+ Configure… Konfigurieren…
+ Not supported in FilmCraft yet In FilmCraft noch nicht unterstützt
+ FilmCraft always composites in linear light FilmCraft setzt immer in linearem Licht zusammen
+ Loop marked range Markierten Bereich in Schleife
+ Play Source Quelle abspielen
+ Source Play/Stop Quelle Wiedergabe/Stopp
+ Stop Source Quelle stoppen
+ New Sequence Neue Sequenz
+ Tracks Spuren
+ tracks Spuren
+ Clear Transition Übergang entfernen
+ Set Transition Duration Übergangsdauer festlegen
+ Active Aktiv
+ Appearance Mode Darstellungsmodus
+ Dark Theme Dunkles Design
+ Light Theme Helles Design
+ Sync with system Mit System synchronisieren
+ UI Scale Skalierung der Oberfläche
+ Auto (system) Automatisch (System)
+ In In
+ Out Out
+ Fill Type Füllungsart
+ Gradient Angle Verlaufswinkel
+ Linear Gradient Linearer Verlauf
+ Solid Vollton
+ GPU Rendering GPU-Rendering
+ Composite on the GPU when available Auf der GPU zusammensetzen, wenn verfügbar
+ Text to Speech Text zu Sprache
+ Edit Narration Erzählung bearbeiten
+ Dock Panel Bedienfeld andocken
+ Undock Panel Bedienfeld abdocken
+ Docking Action Andockaktion
+ Resize floating panel Größe des schwebenden Bedienfelds ändern
+ Get Project Notes Projektnotizen abrufen
+ Edit Project Notes Projektnotizen bearbeiten
+ Notes for this project: to-dos, instructions, frame numbers… Saved with the project. Notizen zu diesem Projekt: Aufgaben, Anweisungen, Framenummern… Werden mit dem Projekt gespeichert.
+ Use Effect Shutter Angle Verschlusswinkel des Effekts verwenden
+ Appearance Settings… Darstellungseinstellungen…
+ Add to favorites Zu Favoriten hinzufügen
+ Remove from favorites Aus Favoriten entfernen
+ Compression Kompression
+ ZIP (1 scan line) ZIP (1 Zeile)
+ ZIP (16 scan lines) ZIP (16 Zeilen)
+ Safe graphics mode: {mode} Sicherer Grafikmodus: {mode}
+ An earlier start failed with the default graphics. Updating the graphics driver usually fixes this. Ein früherer Start mit der Standardgrafik ist fehlgeschlagen. Meist hilft es, den Grafiktreiber zu aktualisieren.
+ Use Default Graphics Standardgrafik verwenden
+ The default graphics are used from the next start. Die Standardgrafik wird ab dem nächsten Start verwendet.
+ DirectX 12 only Nur DirectX 12
+ software rendering Software-Rendering
+ Label Color Presets Vorgaben für Markierungsfarben
+ {name} (Modified) {name} (geändert)
+ Revert to the preset's colors and names Auf die Farben und Namen der Vorgabe zurücksetzen
+ Import a preset file… Vorgabedatei importieren…
+ Export the labels to a preset file… Farbmarkierungen in eine Vorgabedatei exportieren…
+ Show the presets folder Vorgabenordner anzeigen
+ Delete this preset Diese Vorgabe löschen
+ Opens in your web browser: {url} Wird in deinem Webbrowser geöffnet: {url}
+ Saves this session's log and shows it in your file manager. Speichert das Protokoll dieser Sitzung und zeigt es in deinem Dateimanager.
+ Shows a report on this computer. Zeigt einen Bericht über diesen Computer.
+ Shows the version, community links and credits in a FilmCraft window. Zeigt Version, Community-Links und Credits in einem FilmCraft-Fenster.
+ Couldn't open your web browser Dein Webbrowser konnte nicht geöffnet werden
+ Open this address in your browser yourself: Öffne diese Adresse selbst in deinem Browser:
diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv
index 0af8835d1..2ac92decc 100644
--- a/crates/ui-egui/src/i18n/es.tsv
+++ b/crates/ui-egui/src/i18n/es.tsv
@@ -1266,6 +1266,7 @@
59.94 fps Non Drop-Frame 59,94 fps sin eliminación de fotogramas
ASC CDL ASC CDL
Accessible color contrast Contraste de color accesible
+ Animate zoom, scrolling and menus Animar el zoom, el desplazamiento y los menús
Action-Safe Margin Margen seguro de acción
Active Monitor Monitor activo
Add Añadir
@@ -3610,3 +3611,9 @@
Shows the version, community links and credits in a FilmCraft window. Muestra la versión, los enlaces de la comunidad y los créditos en una ventana de FilmCraft.
Couldn't open your web browser No se pudo abrir el navegador web
Open this address in your browser yourself: Abre esta dirección tú mismo en el navegador:
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom Restablecer zoom de la interfaz
+ Track Color Color de pista
+ Open a sequence to search its graphics Abre una secuencia para buscar en sus gráficos
+ No text graphics in this sequence. Add text with the Type tool. Esta secuencia no tiene gráficos con texto. Añade texto con la herramienta Texto.
+ No matching text. Ningún texto coincide.
diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv
index 1075b0c15..6778b0322 100644
--- a/crates/ui-egui/src/i18n/fr.tsv
+++ b/crates/ui-egui/src/i18n/fr.tsv
@@ -1266,6 +1266,7 @@
59.94 fps Non Drop-Frame 59,94 fps non-drop frame
ASC CDL ASC CDL
Accessible color contrast Contraste des couleurs accessible
+ Animate zoom, scrolling and menus Animer le zoom, le défilement et les menus
Action-Safe Margin Marge de sécurité de l'action
Active Monitor Moniteur actif
Add Ajouter
@@ -3577,3 +3578,9 @@
Export the labels to a preset file… Exporter les étiquettes dans un fichier de paramètre prédéfini…
Show the presets folder Afficher le dossier des paramètres prédéfinis
Delete this preset Supprimer ce paramètre prédéfini
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom Réinitialiser le zoom de l'interface
+ Track Color Couleur de la piste
+ Open a sequence to search its graphics Ouvrez une séquence pour rechercher dans ses graphiques
+ No text graphics in this sequence. Add text with the Type tool. Aucun graphique avec du texte dans cette séquence. Ajoutez du texte avec l'outil Texte.
+ No matching text. Aucun texte ne correspond.
diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv
index 508a6e9d4..8ffc4f5b3 100644
--- a/crates/ui-egui/src/i18n/id.tsv
+++ b/crates/ui-egui/src/i18n/id.tsv
@@ -1271,6 +1271,7 @@
59.94 fps Non Drop-Frame 59,94 fps Non Drop-Frame
ASC CDL ASC CDL
Accessible color contrast Kontras warna yang aksesibel
+ Animate zoom, scrolling and menus Animasikan zoom, gulir, dan menu
Action-Safe Margin Margin Aman Aksi
Active Monitor Monitor Aktif
Add Tambah
@@ -3575,3 +3576,9 @@
Appearance Settings… Pengaturan Tampilan…
Add to favorites Tambahkan ke favorit
Remove from favorites Hapus dari favorit
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom Atur Ulang Zoom Antarmuka
+ Track Color Warna Trek
+ Open a sequence to search its graphics Buka sekuens untuk mencari di grafisnya
+ No text graphics in this sequence. Add text with the Type tool. Tidak ada grafis teks di sekuens ini. Tambahkan teks dengan alat Teks.
+ No matching text. Tidak ada teks yang cocok.
diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv
index 22d47ccbd..ef02460c3 100644
--- a/crates/ui-egui/src/i18n/it.tsv
+++ b/crates/ui-egui/src/i18n/it.tsv
@@ -1263,6 +1263,7 @@
59.94 fps Non Drop-Frame 59,94 fps non drop-frame
ASC CDL ASC CDL
Accessible color contrast Contrasto dei colori accessibile
+ Animate zoom, scrolling and menus Anima zoom, scorrimento e menu
Action-Safe Margin Margine di sicurezza azione
Active Monitor Monitor attivo
Add Aggiungi
@@ -3601,3 +3602,9 @@
Shows the version, community links and credits in a FilmCraft window. Mostra la versione, i link della community e i riconoscimenti in una finestra di FilmCraft.
Couldn't open your web browser Impossibile aprire il browser web
Open this address in your browser yourself: Apri tu questo indirizzo nel browser:
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom Reimposta zoom dell'interfaccia
+ Track Color Colore traccia
+ Open a sequence to search its graphics Apri una sequenza per cercare nelle sue grafiche
+ No text graphics in this sequence. Add text with the Type tool. Nessuna grafica con testo in questa sequenza. Aggiungi testo con lo strumento Testo.
+ No matching text. Nessun testo corrispondente.
diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv
index b6a7fb8a2..d0fb3d4e7 100644
--- a/crates/ui-egui/src/i18n/ja.tsv
+++ b/crates/ui-egui/src/i18n/ja.tsv
@@ -1260,6 +1260,7 @@
59.94 fps Non Drop-Frame 59.94 fps ノンドロップフレーム
ASC CDL ASC CDL
Accessible color contrast アクセシビリティに配慮したカラーコントラスト
+ Animate zoom, scrolling and menus ズーム、スクロール、メニューをアニメーション表示
Action-Safe Margin アクションセーフの余白
Active Monitor アクティブなモニター
Add 加算
@@ -3609,3 +3610,9 @@
Shows the version, community links and credits in a FilmCraft window. バージョン、コミュニティへのリンク、クレジットを FilmCraft のウィンドウに表示します。
Couldn't open your web browser ウェブブラウザーを開けませんでした
Open this address in your browser yourself: このアドレスをご自身でブラウザーで開いてください:
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom インターフェイスのズームをリセット
+ Track Color トラックカラー
+ Open a sequence to search its graphics シーケンスを開くとグラフィックスを検索できます
+ No text graphics in this sequence. Add text with the Type tool. このシーケンスにはテキストのグラフィックスがありません。文字ツールでテキストを追加してください。
+ No matching text. 一致するテキストはありません。
diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv
index 20341b9a6..73d5adf68 100644
--- a/crates/ui-egui/src/i18n/ko.tsv
+++ b/crates/ui-egui/src/i18n/ko.tsv
@@ -76,6 +76,7 @@
About FilmCraft FilmCraft 정보
Accent Color 강조 색상
Accessible color contrast 접근성 색상 대비
+ Animate zoom, scrolling and menus 확대/축소, 스크롤 및 메뉴 애니메이션
Action and Title Safe Areas 액션 및 제목 안전 영역
Action Safe Area 액션 안전 영역
Action-Safe Margin 액션 세이프 여백
@@ -3596,3 +3597,9 @@
Shows the version, community links and credits in a FilmCraft window. FilmCraft 창에 버전, 커뮤니티 링크, 제작진을 보여 줍니다.
Couldn't open your web browser 웹 브라우저를 열 수 없습니다
Open this address in your browser yourself: 이 주소를 브라우저에서 직접 여세요:
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom 인터페이스 확대/축소 재설정
+ Track Color 트랙 색상
+ Open a sequence to search its graphics 그래픽을 검색하려면 시퀀스를 여세요
+ No text graphics in this sequence. Add text with the Type tool. 이 시퀀스에는 텍스트 그래픽이 없습니다. 문자 도구로 텍스트를 추가하세요.
+ No matching text. 일치하는 텍스트가 없습니다.
diff --git a/crates/ui-egui/src/i18n/mod.rs b/crates/ui-egui/src/i18n/mod.rs
index 2688f545b..eef1c3682 100644
--- a/crates/ui-egui/src/i18n/mod.rs
+++ b/crates/ui-egui/src/i18n/mod.rs
@@ -1152,16 +1152,17 @@ mod tests {
}
}
- /// German covers at least the core menus (`core_menu_labels`, the top-level menus and the native
- /// macOS app menu); every entry must still be a menu label.
+ /// German covers the whole interface (every entry of the Spanish catalog, the native macOS app
+ /// menu included), but, like French, the tests require only the core menus and the native app
+ /// menu, so strings added later show in English until they are translated. Every entry must
+ /// still have a Spanish counterpart: a renamed or removed source would otherwise leave a dead
+ /// German entry.
#[test]
- fn german_entries_cover_the_original_menu_catalog() {
- let app = crate::FilmcraftApp::new(filmcraft_engine::Session::default());
- let items = crate::menus::menu_items(&app);
- let known = |text: &str| crate::menus::MENUS.contains(&text) || items.iter().any(|it| it.label == text || it.path.iter().any(|p| p == text));
- let (entries, _) = catalog::parse_entries(include_str!("de.tsv"));
- for (_, en, _) in entries {
- assert!(known(&en) || crate::menus::NATIVE_APP_MENU.contains(&en.as_str()), "not a menu label: {en}");
+ fn german_covers_the_menus_and_has_no_dead_entries() {
+ let (entries, errors) = catalog::parse_entries(include_str!("de.tsv"));
+ assert!(errors.is_empty(), "{errors:?}");
+ for (ctx, en, _) in &entries {
+ assert!(ctx.is_empty() && Language::Es.has(en), "German entry without a Spanish one: {ctx:?} {en:?}");
}
for en in core_menu_labels() {
assert!(Language::De.has(&en), "missing German menu label: {en}");
@@ -1172,6 +1173,21 @@ mod tests {
}
assert_eq!(Language::De.tr("Settings"), "Voreinstellungen");
assert_eq!(Language::De.tr("Quit FilmCraft"), "FilmCraft beenden");
+ // beyond the menus: panels, effects and their parameters, settings, status messages
+ for (en, de) in [
+ ("Gaussian Blur", "Gaußscher Weichzeichner"),
+ ("Audio Track Mixer", "Audiospur-Mischpult"),
+ ("Sequence", "Sequenz"),
+ ("Playhead", "Abspielposition"),
+ ("Keyboard Shortcuts", "Tastenkürzel"),
+ ("{n} min ago", "vor {n} Min."),
+ ] {
+ assert_eq!(Language::De.tr(en), de);
+ }
+ set_current(Language::De);
+ assert!(matches_query("Gaussian Blur", "weichzeichner"));
+ assert!(matches_query("Gaussian Blur", "gaussian"));
+ set_current(Language::En);
}
/// French covers the whole interface (the Spanish catalog's entries and the native macOS
@@ -1367,6 +1383,16 @@ mod tests {
assert_bundled_fonts_cover(alphabet.chars().chain(Language::Fr.name().chars()).chain(letters));
}
+ #[test]
+ fn german_renders_with_bundled_fonts() {
+ let (entries, _) = catalog::parse_entries(include_str!("de.tsv"));
+ // every German letter and quotation mark, even ones no entry uses yet, and every letter,
+ // dash and ellipsis the entries use (symbols such as ✔ come from the English sources)
+ let alphabet = "ÄÖÜäöüß„“‚‘";
+ let letters = entries.iter().flat_map(|(_, _, de)| de.chars()).filter(|ch| ch.is_alphabetic() || "„“‚‘–—…".contains(*ch));
+ assert_bundled_fonts_cover(alphabet.chars().chain(Language::De.name().chars()).chain(letters));
+ }
+
#[test]
fn indonesian_renders_with_bundled_fonts() {
let (entries, _) = catalog::parse_entries(include_str!("id.tsv"));
diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv
index aeb0e0691..7cbb49a58 100644
--- a/crates/ui-egui/src/i18n/pt-br.tsv
+++ b/crates/ui-egui/src/i18n/pt-br.tsv
@@ -1268,6 +1268,7 @@
59.94 fps Non Drop-Frame 59,94 fps sem drop-frame
ASC CDL ASC CDL
Accessible color contrast Contraste de cores acessível
+ Animate zoom, scrolling and menus Animar zoom, rolagem e menus
Action-Safe Margin Margem de segurança de ação
Active Monitor Monitor ativo
Add Adicionar
@@ -3578,3 +3579,9 @@
# The native macOS application menu (Settings…).
Settings Preferências
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom Redefinir zoom da interface
+ Track Color Cor da trilha
+ Open a sequence to search its graphics Abra uma sequência para pesquisar nos gráficos dela
+ No text graphics in this sequence. Add text with the Type tool. Esta sequência não tem gráficos com texto. Adicione texto com a ferramenta Texto.
+ No matching text. Nenhum texto corresponde.
diff --git a/crates/ui-egui/src/i18n/zh-cn.tsv b/crates/ui-egui/src/i18n/zh-cn.tsv
index 066279eef..244646f47 100644
--- a/crates/ui-egui/src/i18n/zh-cn.tsv
+++ b/crates/ui-egui/src/i18n/zh-cn.tsv
@@ -1254,6 +1254,7 @@
59.94 fps Non Drop-Frame 59.94 fps 非掉帧
ASC CDL ASC CDL
Accessible color contrast 无障碍颜色对比度
+ Animate zoom, scrolling and menus 缩放、滚动和菜单使用动画
Action-Safe Margin 动作安全边距
Active Monitor 活动监视器
Add 添加
@@ -3585,3 +3586,9 @@
Shows the version, community links and credits in a FilmCraft window. 在 FilmCraft 窗口中显示版本、社区链接和致谢。
Couldn't open your web browser 无法打开网页浏览器
Open this address in your browser yourself: 请自行在浏览器中打开此地址:
+# View ▸ Reset Interface Zoom (#2253).
+ Reset Interface Zoom 重置界面缩放
+ Track Color 轨道颜色
+ Open a sequence to search its graphics 打开序列以搜索其中的图形
+ No text graphics in this sequence. Add text with the Type tool. 此序列中没有文本图形。请用文字工具添加文本。
+ No matching text. 没有匹配的文本。
diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs
index e3a644ff8..c838e6fe9 100644
--- a/crates/ui-egui/src/lib.rs
+++ b/crates/ui-egui/src/lib.rs
@@ -39,6 +39,9 @@ pub mod credits;
pub mod dock;
mod dock_shared;
mod dock_ui;
+/// Thumbnail textures kept before the least recently used are freed (each is up to 320 px wide).
+const MAX_THUMB_TEXTURES: usize = 512;
+
pub mod frames;
pub mod graphics_notice;
pub mod header;
@@ -289,6 +292,9 @@ pub struct FilmcraftApp {
pub auto: automation::Registry,
/// Named textures (monitors, thumbnails) with the key they show.
textures: HashMap,
+ /// The UI pass each thumbnail texture was last used in: thumbnails beyond
+ /// [`MAX_THUMB_TEXTURES`] are freed, least recently used first (#1682).
+ thumb_used: HashMap,
control_rx: Option>,
/// One explicit panel reveal; consumed by the custom renderer, never repeated per frame.
pub(crate) pending_panel_raise: Option,
@@ -553,6 +559,7 @@ impl FilmcraftApp {
native_dialog: None,
auto: Default::default(),
textures: HashMap::new(),
+ thumb_used: HashMap::new(),
control_rx: None,
pending_panel_raise: None,
control_input_only: false,
@@ -633,6 +640,7 @@ impl FilmcraftApp {
FrameServer::default_workers(),
));
self.textures.clear();
+ self.thumb_used.clear();
self.tl.reset_media_caches();
// the new frame server needs the Memory settings
self.applied_prefs = None;
@@ -685,6 +693,16 @@ impl FilmcraftApp {
}
}
+ /// View ▸ Reset Interface Zoom: the scale Settings ▸ Appearance ▸ UI Scale asks for (the
+ /// system's with Auto), undoing any session zoom (#2253).
+ /// Returns the zoom factor set (egui reports it from the next pass on).
+ pub(crate) fn reset_ui_zoom(&mut self, ctx: &egui::Context) -> f32 {
+ let native = ctx.native_pixels_per_point().filter(|v| v.is_finite() && *v > 0.0).unwrap_or(1.0);
+ let zoom = self.session.prefs.appearance.ui_scale_factor().map_or(1.0, |scale| scale / native);
+ ctx.set_zoom_factor(zoom);
+ zoom
+ }
+
/// Make the UI follow the settings after they change (theme, tooltips, frame cache budget,
/// play after rendering, audio device).
pub fn apply_prefs(&mut self, ctx: &egui::Context) {
@@ -697,6 +715,11 @@ impl FilmcraftApp {
self.set_theme(ctx, k);
}
}
+ // checked every frame: a theme or font change installs the style again
+ let animation = if self.session.prefs.appearance.animations { theme::ANIMATION_TIME } else { 0.0 };
+ if ctx.global_style().animation_time != animation {
+ ctx.global_style_mut(|s| s.animation_time = animation);
+ }
if self.applied_prefs.as_ref() == Some(&self.session.prefs) {
return;
}
@@ -849,6 +872,13 @@ impl FilmcraftApp {
}
pub fn show_panel(&mut self, p: PanelKind) {
+ // closed while floating: it floats again where it was (#1985); taken before the Timeline's
+ // own restore below docks it
+ let open = self.ui.dock.contains(p) || self.ui.floating.iter().any(|group| group.panels.contains(&p));
+ let refloat = match self.ui.closed_floating.iter().position(|(k, _)| *k == p) {
+ Some(i) if !open => Some(self.ui.closed_floating.remove(i).1),
+ _ => None,
+ };
if p == PanelKind::Timeline && !self.ui.floating.iter().any(|group| group.panels.contains(&p)) {
self.ui.dock.restore_timeline();
}
@@ -873,6 +903,15 @@ impl FilmcraftApp {
};
self.ui.dock.open_near(p, near);
}
+ if let Some(rect) = refloat.filter(|r| r.iter().all(|v| v.is_finite())) {
+ let rect = [rect[0], rect[1], rect[2].max(160.0), rect[3].max(120.0)];
+ if let Err(e) = self.apply_dock(craft_ui::docking::Action::Float { panel: p, rect }) {
+ // refused (it is the only docked panel left): it stays docked, and its floating
+ // place is kept rather than lost
+ log::warn!("could not float {} again: {e}", p.id());
+ self.ui.closed_floating.push((p, rect));
+ }
+ }
let _ = self.apply_dock(craft_ui::docking::Action::Activate { panel: p });
self.ui.focused = p;
}
@@ -1251,12 +1290,40 @@ impl FilmcraftApp {
let name = format!("thumb-{}-{}-{}", item.0, frame, width);
if let Some(img) = self.frames.get(&key) {
let id = self.texture_for(ctx, &name, key, &img);
+ self.thumb_touched(ctx, &name);
return Some((id, egui::vec2(img.w as f32, img.h as f32)));
}
let scale = width as f32 / src_w.max(1) as f32;
let project = self.session.project.clone();
self.frames.request(key, rate.tick_of(frame), scale, &project, 50);
- self.texture_existing(&name)
+ let shown = self.texture_existing(&name);
+ if shown.is_some() {
+ self.thumb_touched(ctx, &name);
+ }
+ shown
+ }
+
+ /// Note that thumbnail texture `name` is used in this pass, and free the least recently used
+ /// thumbnails once there are more than [`MAX_THUMB_TEXTURES`]: every frame shown in a timeline
+ /// tile or a hover scrub got a texture of its own that was never freed (#1682).
+ fn thumb_touched(&mut self, ctx: &egui::Context, name: &str) {
+ let pass = ctx.cumulative_pass_nr();
+ if self.thumb_used.insert(name.to_string(), pass).is_some() || self.thumb_used.len() <= MAX_THUMB_TEXTURES {
+ return;
+ }
+ // down to three quarters, never a thumbnail already drawn in this pass
+ let mut old: Vec<(u64, String)> = self.thumb_used.iter().filter(|(_, p)| **p < pass).map(|(n, p)| (*p, n.clone())).collect();
+ old.sort_unstable();
+ let excess = self.thumb_used.len().saturating_sub(MAX_THUMB_TEXTURES * 3 / 4);
+ for (_, n) in old.into_iter().take(excess) {
+ self.thumb_used.remove(&n);
+ self.textures.remove(&n);
+ }
+ }
+
+ /// The number of thumbnail textures held (tests, diagnostics).
+ pub fn thumbnail_textures(&self) -> usize {
+ self.textures.keys().filter(|n| n.starts_with("thumb-")).count()
}
// ---------------------------------------------------------------- files
diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs
index 6be3c6d62..1f37d2804 100644
--- a/crates/ui-egui/src/menus.rs
+++ b/crates/ui-egui/src/menus.rs
@@ -54,6 +54,7 @@ pub const UI_COMMANDS: &[UiCommand] = &[
uic!("view.zoomIn", "Zoom In", ["View"], Some("=")),
uic!("view.zoomOut", "Zoom Out", ["View"], Some("-")),
uic!("view.zoomToSequence", "Zoom to Sequence", ["View"], Some("\\")),
+ uic!("view.resetInterfaceZoom", "Reset Interface Zoom", ["View"], None),
uic!("view.playbackRes.full", "Full", ["View", "Playback Resolution"], None),
uic!("view.playbackRes.half", "1/2", ["View", "Playback Resolution"], None),
uic!("view.playbackRes.quarter", "1/4", ["View", "Playback Resolution"], None),
@@ -420,6 +421,12 @@ pub fn invoke(app: &mut FilmcraftApp, ctx: &egui::Context, id: &str, mut params:
app.ui.timeline.fit_pending = true;
return Ok(Value::Null);
}
+ // the whole interface back to Settings ▸ Appearance ▸ UI Scale, after Ctrl+Plus or a mouse
+ // mapped to page zoom scaled it (#2253)
+ "view.resetInterfaceZoom" => {
+ let zoom = app.reset_ui_zoom(ctx);
+ return Ok(json!({"zoom": zoom}));
+ }
"mode.import" => {
app.ui.mode = Mode::Import;
return Ok(Value::Null);
@@ -846,6 +853,16 @@ pub fn bindings(app: &FilmcraftApp) -> Vec {
let shifted: Vec =
v.iter().filter(|b| b.0.shift).filter_map(|(m, k, id, p)| shifted_key(*k).map(|k2| (*m, k2, id.clone(), p.clone()))).collect();
v.extend(shifted);
+ // `+` is the `=` key with Shift on US layouts and its own key on others and the keypad: a chord
+ // on `=` takes it too, unless something is bound to `+` itself. Otherwise Ctrl+Plus fell
+ // through to egui's interface zoom while Ctrl+- and Ctrl+0 were taken by FilmCraft
+ // shortcuts, so the interface grew and could not shrink back (#2253).
+ let plus: Vec = v
+ .iter()
+ .filter(|(m, k, _, p)| *k == egui::Key::Equals && !v.iter().any(|(m2, k2, _, p2)| *k2 == egui::Key::Plus && m2 == m && p2 == p))
+ .map(|(m, _, id, p)| (*m, egui::Key::Plus, id.clone(), p.clone()))
+ .collect();
+ v.extend(plus);
v.sort_by_key(|(m, ..)| std::cmp::Reverse(specificity(*m)));
v
}
diff --git a/crates/ui-egui/src/panels/effect_controls.rs b/crates/ui-egui/src/panels/effect_controls.rs
index b829a25fc..887768294 100644
--- a/crates/ui-egui/src/panels/effect_controls.rs
+++ b/crates/ui-egui/src/panels/effect_controls.rs
@@ -197,9 +197,18 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
// Premiere lists the fixed effects (Motion, Opacity, Time Remapping / Volume…) first.
let mut order: Vec = (0..it.effects.len()).collect();
order.sort_by_key(|i| !it.effects[*i].def().is_some_and(|d| d.intrinsic));
+ let mut after_fixed = false;
for idx in order {
let e = &it.effects[idx];
let Some(def) = e.def() else { continue };
+ // the first effect added from the library after the fixed ones gets a line on top
+ // (#2328); drawn on its edge, so no row moves
+ let first_added = if def.intrinsic {
+ after_fixed = true;
+ false
+ } else {
+ std::mem::take(&mut after_fixed)
+ };
let key = format!("{}:{}", clip.0, idx);
let open = !app.ui.collapsed_fx.contains(&key);
let selected = app.session.state.selected_effect.as_ref().is_some_and(|s| s.clip == clip && s.index(&it.effects) == Some(idx));
@@ -210,6 +219,12 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
bui.painter().rect_filled(crate::panels::effect_controls::row_fill(r), 0.0, t.hover);
}
row_line(bui, r, &lane, &t);
+ if first_added {
+ let line = Rect::from_min_max(pos2(r.min.x, r.min.y - 1.0), pos2(r.max.x, r.min.y + 1.0));
+ bui.painter().rect_filled(line, 0.0, t.accent.gamma_multiply(0.8));
+ let which = if *kind == TrackKind::Video { "video" } else { "audio" };
+ app.auto.add(&format!("effectControls.addedEffects.{which}"), line, "Added effects");
+ }
// only the arrow twirls the effect open or shut; the rest of the header selects it
let tw = Rect::from_center_size(pos2(r.min.x + 10.0, r.center().y), vec2(10.0, 10.0));
icons::paint(bui.painter(), tw, if open { Icon::ChevronDown } else { Icon::ChevronRight }, t.text_dim);
diff --git a/crates/ui-egui/src/panels/effects.rs b/crates/ui-egui/src/panels/effects.rs
index c4f5c15bb..da0e66db3 100644
--- a/crates/ui-egui/src/panels/effects.rs
+++ b/crates/ui-egui/src/panels/effects.rs
@@ -87,8 +87,9 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
if resp.hovered() {
ui.painter().rect_filled(r, 0.0, t.hover);
}
- let x = r.min.x + 46.0;
- let icon_r = Rect::from_center_size(pos2(x - 10.0, r.center().y), vec2(13.0, 13.0));
+ // inside the top folder, or inside its sub-folder
+ let x = r.min.x + tree_x(if s.is_empty() { 1 } else { 2 }) + 30.0;
+ let icon_r = Rect::from_center_size(pos2(x - 12.0, r.center().y), vec2(13.0, 13.0));
let is_tr = matches!(d.kind, filmcraft_project::EffectKind::VideoTransition | filmcraft_project::EffectKind::AudioTransition);
ui.painter().rect_stroke(icon_r, 2.0, egui::Stroke::new(1.0, t.text_dim), egui::StrokeKind::Inside);
if is_tr {
@@ -139,6 +140,13 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
}
}
+/// Where a tree row at `depth` starts (its chevron): folders at 0 (top) and 1 (sub-folders), and
+/// what a folder holds one level deeper than the folder (#2329), so an effect is never level with,
+/// or left of, the folder it is in. A row's icon is centred 18 points in, its label 30.
+pub(crate) fn tree_x(depth: usize) -> f32 {
+ 8.0 + depth as f32 * 16.0
+}
+
fn folder_row(app: &mut FilmcraftApp, ui: &mut egui::Ui, key: &str, depth: usize, filter: &str) -> bool {
let t = app.tokens;
let open = !filter.is_empty() || app.ui.expanded_fx.iter().any(|k| k == key);
@@ -146,7 +154,7 @@ fn folder_row(app: &mut FilmcraftApp, ui: &mut egui::Ui, key: &str, depth: usize
if resp.hovered() {
ui.painter().rect_filled(r, 0.0, t.hover);
}
- let x = r.min.x + 8.0 + depth as f32 * 16.0;
+ let x = r.min.x + tree_x(depth);
icons::paint(
ui.painter(),
Rect::from_center_size(pos2(x + 4.0, r.center().y), vec2(10.0, 10.0)),
@@ -240,7 +248,8 @@ fn lumetri_rows(app: &mut FilmcraftApp, ui: &mut egui::Ui, filter: &str) -> Opti
ui.painter().rect_filled(r, 0.0, t.hover);
}
let tex = preset_texture(app, ui.ctx(), p, 64);
- let tr = Rect::from_min_size(pos2(r.min.x + 40.0, r.min.y + 3.0), vec2(32.0, 18.0));
+ // inside a Lumetri Presets sub-folder: one level deeper than it
+ let tr = Rect::from_min_size(pos2(r.min.x + tree_x(2) + 12.0, r.min.y + 3.0), vec2(32.0, 18.0));
ui.painter().image(tex, tr, Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), Color32::WHITE);
ui.painter().text(pos2(tr.max.x + 8.0, r.center().y), Align2::LEFT_CENTER, crate::i18n::t(p.name), Tokens::ui(12.0), t.text);
app.auto.add(&format!("effects.lumetriPreset.{}", p.name), r, p.name);
diff --git a/crates/ui-egui/src/panels/graphics.rs b/crates/ui-egui/src/panels/graphics.rs
index 1b9e5438c..7fb91b98d 100644
--- a/crates/ui-egui/src/panels/graphics.rs
+++ b/crates/ui-egui/src/panels/graphics.rs
@@ -831,7 +831,20 @@ pub fn monitor_overlay(app: &mut FilmcraftApp, ui: &mut egui::Ui, pic: Rect, fra
let p = resp.interact_pointer_pos().unwrap_or(pic.center());
let in_edit = edit_view.is_some_and(|v| v.hit(p));
match tool {
- _ if in_edit => {}
+ // a click in the text being edited puts the caret there (Shift extends the selection),
+ // as a press that becomes a drag already does (#2430)
+ _ if in_edit => {
+ if let (Some(v), Some(mut ed)) = (edit_view, editing.clone())
+ && let Some(tp) = text_of(&v.spec)
+ && let Some((x, y)) = v.to_local(p)
+ {
+ ed.caret = text_layout(tp).hit(x, y);
+ if !ui.input(|i| i.modifiers.shift) {
+ ed.anchor = ed.caret;
+ }
+ app.ui.gfx_edit = Some(ed);
+ }
+ }
Tool::Type | Tool::VerticalType => {
if let Some(v) = views.iter().find(|v| v.is_text() && v.hit(p)) {
start_edit_at(app, ui, v, p, &mut actions);
@@ -910,8 +923,8 @@ pub fn monitor_overlay(app: &mut FilmcraftApp, ui: &mut egui::Ui, pic: Rect, fra
painter.add(egui::Shape::convex_polygon(q.to_vec(), Color32::from_rgba_unmultiplied(80, 140, 255, 90), Stroke::NONE));
}
let (x, base, li) = l.caret(caret);
- let line = &l.lines[li.min(l.lines.len() - 1)];
- let (a, b) = (sp(&v.to_screen, x, base - line.ascent), sp(&v.to_screen, x, base + line.descent));
+ let (ascent, descent) = l.lines.get(li.min(l.lines.len().saturating_sub(1))).map_or((0.0, 0.0), |line| (line.ascent, line.descent));
+ let (a, b) = (sp(&v.to_screen, x, base - ascent), sp(&v.to_screen, x, base + descent));
painter.line_segment([a, b], Stroke::new(1.5, Color32::WHITE));
painter.line_segment([a + vec2(1.0, 0.0), b + vec2(1.0, 0.0)], Stroke::new(0.5, Color32::BLACK));
let er = Rect::from_points(&v.quad()).union(Rect::from_two_pos(a, b));
@@ -1198,6 +1211,8 @@ fn color32(c: [f32; 4]) -> Color32 {
struct Ctx<'a> {
clip: ClipId,
layer: usize,
+ /// The layer's index in the clip's effect list (what `effects.toggleAnimation` addresses).
+ eidx: usize,
e: &'a EffectInstance,
mt: Tick,
t: Tokens,
@@ -1245,12 +1260,37 @@ impl Ctx<'_> {
);
(r, v)
}
+ /// The stopwatch in front of an animatable property's label (#2358): turns keyframing on or
+ /// off at the playhead, like the one in Effect Controls. While a property animates, changing
+ /// it here adds or updates a keyframe at the playhead instead of changing it everywhere. A
+ /// Type-tool selection edits the selected characters, which have no keyframes: no stopwatch.
+ fn stopwatch(&mut self, ui: &egui::Ui, row: Rect, id: &str) {
+ let animatable = self.e.def().and_then(|d| d.param(id)).is_some_and(|d| d.animatable);
+ if !animatable || (self.range.is_some() && char_style_key(id).is_some()) {
+ return;
+ }
+ let animated = self.e.params.get(id).is_some_and(|p| p.is_animated());
+ let sw = Rect::from_center_size(pos2(row.min.x + 8.0, row.center().y), vec2(12.0, 12.0));
+ let resp = ui.interact(sw.expand(2.0), egui::Id::new(("gfxsw", self.clip.0, self.layer, id)), Sense::click()).on_hover_text(tl!("Toggle animation"));
+ let tint = if animated {
+ self.t.accent
+ } else if resp.hovered() {
+ self.t.text
+ } else {
+ self.t.text_faint
+ };
+ icons::paint(ui.painter(), sw, Icon::Stopwatch, tint);
+ self.autos.push((format!("graphics.prop.{id}.stopwatch"), sw, "Toggle animation".to_string()));
+ if resp.clicked() {
+ self.actions.push(("effects.toggleAnimation".into(), json!({"clip": self.clip.0, "effect": self.eidx, "param": id})));
+ }
+ }
fn number(&mut self, ui: &mut egui::Ui, label: &str, id: &str, speed: f64, range: (f64, f64), dec: usize, unit: &str) {
let v = pv(self.e, id, self.mt).as_f64().unwrap_or(0.0);
let (r, mut vui) = self.row(ui, label);
let (resp, nv) = crate::widgets::hot_number(&mut vui, egui::Id::new(("gfxp", self.clip.0, self.layer, id)), v, speed, range, dec, unit, &self.t);
self.auto(id, resp.rect, label);
- let _ = r;
+ self.stopwatch(ui, r, id);
if let Some(nv) = nv {
self.set(id, json!(nv));
}
@@ -1265,7 +1305,8 @@ impl Ctx<'_> {
}
fn point(&mut self, ui: &mut egui::Ui, label: &str, id: &str) {
let v = pv(self.e, id, self.mt).as_vec2().unwrap_or_default();
- let (_, mut vui) = self.row(ui, label);
+ let (r, mut vui) = self.row(ui, label);
+ self.stopwatch(ui, r, id);
let (rx, nx) = crate::widgets::hot_number(
&mut vui,
egui::Id::new(("gfxp", self.clip.0, self.layer, id, "x")),
@@ -1565,7 +1606,7 @@ pub fn properties(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
let ch = |b: usize| text.get(..b.min(text.len())).map_or(0, |s| s.chars().count());
Some((ch(ed.caret.min(ed.anchor)), ch(ed.caret.max(ed.anchor))))
});
- let mut cx = Ctx { clip, layer: l, e, mt, t, actions: Vec::new(), autos: Vec::new(), range };
+ let mut cx = Ctx { clip, layer: l, eidx: idx[l], e, mt, t, actions: Vec::new(), autos: Vec::new(), range };
if section(ui, app, "Responsive Design - Position", &t) {
crate::panels::graphics_templates::responsive_position(app, ui, clip, &it, l, &mut cx.autos, &mut cx.actions);
}
@@ -1810,7 +1851,7 @@ pub fn properties(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
for (cmd, mut p) in actions {
// a drag of a property is one undo step: the first change of each press begins a new one,
// the rest fold into it (like Effect Controls, #201 / #887)
- if cmd == "graphics.set" && down {
+ if matches!(cmd.as_str(), "graphics.set" | "graphics.setCharStyle") && down {
p["merge"] = json!(true);
p["begin"] = json!(begun != press);
wrote = true;
diff --git a/crates/ui-egui/src/panels/multicam.rs b/crates/ui-egui/src/panels/multicam.rs
index f8ebe9ecc..34ffae02d 100644
--- a/crates/ui-egui/src/panels/multicam.rs
+++ b/crates/ui-egui/src/panels/multicam.rs
@@ -70,8 +70,10 @@ pub fn route(app: &mut FilmcraftApp, id: &str, params: &Value) -> Option = app.session.state.project_selection.iter().map(|i| i.0).collect();
- let first = app.session.state.project_selection.first().and_then(|i| app.session.project.item(*i)).map(|i| i.name.clone()).unwrap_or_default();
+ // the Project panel's selection, or the media of the clips selected in the Timeline (#1362)
+ let selected = filmcraft_engine::multicam::selected_items(&app.session);
+ let items: Vec = selected.iter().map(|i| i.0).collect();
+ let first = selected.first().and_then(|i| app.session.project.item(*i)).map(|i| i.name.clone()).unwrap_or_default();
let name = match kind {
"merge" => tlf!("{first} - Merged", first),
"multicam" => tlf!("{first} Multicam", first),
diff --git a/crates/ui-egui/src/panels/presets.rs b/crates/ui-egui/src/panels/presets.rs
index b6639bda3..9867de393 100644
--- a/crates/ui-egui/src/panels/presets.rs
+++ b/crates/ui-egui/src/panels/presets.rs
@@ -26,7 +26,8 @@ pub fn folder_rows(app: &mut FilmcraftApp, ui: &mut egui::Ui, filter: &str) -> O
if resp.hovered() {
ui.painter().rect_filled(r, 0.0, t.hover);
}
- let x = r.min.x + 30.0;
+ // inside the Presets folder: icon and label one level deeper than it (#2329)
+ let x = r.min.x + crate::panels::effects::tree_x(1) + 18.0;
icons::paint(
ui.painter(),
Rect::from_center_size(pos2(x, r.center().y), vec2(13.0, 13.0)),
diff --git a/crates/ui-egui/src/panels/text.rs b/crates/ui-egui/src/panels/text.rs
index 6de9c6139..b6eaca3c9 100644
--- a/crates/ui-egui/src/panels/text.rs
+++ b/crates/ui-egui/src/panels/text.rs
@@ -1,4 +1,6 @@
-//! The Text panel: Transcript / Captions / Graphics tabs. The Captions tab lists the caption
+//! The Text panel: Transcript / Captions / Graphics tabs. The Graphics tab lists the text of every
+//! text layer in the sequence's graphics (#1487), with a search; clicking an entry goes to its clip
+//! and selects the layer, and the text edits in place (`graphics.set`). The Captions tab lists the caption
//! segments of a caption track with editable in/out timecodes and text, a toolbar (add, split,
//! merge, delete), track choice and the track style. Every edit dispatches a `captions.*` engine
//! command; every widget registers an automation id (`text.*`). The Transcript tab shows the
@@ -57,7 +59,7 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
match app.ui.text_tab.as_str() {
"Captions" => captions(app, ui, body),
"Transcript" => transcript(app, ui, body),
- _ => crate::dock::placeholder(ui, body, &t, tl!("Graphics text search arrives with M10.1–M10.2")),
+ _ => graphics(app, ui, body),
}
}
@@ -282,6 +284,163 @@ fn captions(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
run(app, ui, actions);
}
+/// A text layer of a graphic clip in the active sequence, for the Graphics tab.
+#[derive(Clone, Debug, PartialEq)]
+pub struct GraphicText {
+ pub clip: filmcraft_project::ClipId,
+ /// The layer's number among the clip's layers (what `graphics.set` / `graphics.selectLayer` take).
+ pub layer: usize,
+ pub start: filmcraft_time::Tick,
+ /// The track's label (`V2`).
+ pub track: String,
+ /// The layer's own name, when it has one.
+ pub name: Option,
+ pub text: String,
+ /// The timeline time the text was read at (the playhead, or the clip's start when the
+ /// playhead is outside the clip): an edit is written there, so keyframed text changes the
+ /// value that is shown.
+ pub at: filmcraft_time::Tick,
+}
+
+/// Every text layer of every graphic clip in `seq`, in timeline order (then lower tracks first,
+/// then paint order), with its text at `at` when that falls in the clip (Source Text keyframes
+/// hold), else at the clip's first frame.
+pub fn graphic_texts(seq: &filmcraft_project::Sequence, at: filmcraft_time::Tick) -> Vec {
+ use filmcraft_project::graphic::{TEXT_LAYER, layer_indices};
+ let mut out = Vec::new();
+ for (ti, track) in seq.video_tracks.iter().enumerate() {
+ for it in &track.items {
+ let t = if it.start <= at && at < it.end() { at } else { it.start };
+ let mt = it.effect_time_at(t);
+ for (layer, ei) in layer_indices(&it.effects).into_iter().enumerate() {
+ let Some(e) = it.effects.get(ei).filter(|e| e.effect == TEXT_LAYER) else { continue };
+ let text = match e.param("text").map(|p| p.value_at(mt)) {
+ Some(filmcraft_project::ParamValue::Text(s)) => s,
+ _ => String::new(),
+ };
+ let name = match e.param("name").map(|p| p.value.clone()) {
+ Some(filmcraft_project::ParamValue::Text(n)) if !n.trim().is_empty() => Some(n),
+ _ => None,
+ };
+ out.push((ti, GraphicText { clip: it.id, layer, start: it.start, track: format!("V{}", ti + 1), name, text, at: t }));
+ }
+ }
+ }
+ out.sort_by(|(ta, a), (tb, b)| a.start.cmp(&b.start).then(ta.cmp(tb)).then(a.layer.cmp(&b.layer)));
+ out.into_iter().map(|(_, g)| g).collect()
+}
+
+/// The Graphics tab (#1487): the text of every text layer in the sequence, searchable. The
+/// timecode goes to the clip and selects the layer; the text edits in place.
+fn graphics(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
+ let t = app.tokens;
+ let project = app.session.project.clone();
+ let Some(seq) = app.session.state.active_sequence.and_then(|id| project.sequence(id)) else {
+ crate::dock::placeholder(ui, rect, &t, tl!("Open a sequence to search its graphics"));
+ return;
+ };
+ let (rate, df) = (seq.settings.frame_rate, seq.settings.drop_frame);
+ let tc = |x: filmcraft_time::Tick| format_time(x, rate, df, TimeDisplay::Timecode, 48_000);
+ let ph = app.session.playhead();
+ let entries = graphic_texts(seq, ph);
+ let mut actions: Vec<(String, Value)> = Vec::new();
+ // search
+ let bar = Rect::from_min_size(rect.min + vec2(10.0, 2.0), vec2(rect.width() - 20.0, 26.0));
+ let skey = egui::Id::new("text-gfx-search");
+ let mut search = ui.data(|d| d.get_temp::(skey)).unwrap_or_default();
+ let w = 220.0f32.min(bar.width());
+ let mut child = ui.new_child(egui::UiBuilder::new().max_rect(Rect::from_min_size(bar.min, vec2(w, 24.0))));
+ let sresp = crate::widgets::search_field(&mut child, &mut search, tl!("Search"), w, &t);
+ app.auto.add("text.graphics.search", sresp.rect, "Search graphics text");
+ ui.data_mut(|d| d.insert_temp(skey, search.clone()));
+ let q = search.to_lowercase();
+ // list
+ let list = Rect::from_min_max(pos2(rect.min.x + 6.0, bar.max.y + 8.0), pos2(rect.max.x - 6.0, rect.max.y - 4.0));
+ ui.painter().rect_filled(list, 3.0, t.app_bg);
+ let sel_clips = app.session.state.selection.clone();
+ let sel_layers = app.session.state.graphic_layers.clone();
+ let mut child = ui.new_child(egui::UiBuilder::new().max_rect(list.shrink(4.0)).id_salt("graphics-text-list"));
+ egui::ScrollArea::vertical().auto_shrink([false, false]).id_salt("graphics-text-scroll").show(&mut child, |ui| {
+ ui.set_width(list.width() - 12.0);
+ let mut shown = 0;
+ for (n, g) in entries.iter().enumerate() {
+ if !q.is_empty() && !g.text.to_lowercase().contains(&q) && !g.name.as_deref().unwrap_or("").to_lowercase().contains(&q) {
+ continue;
+ }
+ shown += 1;
+ let key = format!("{}.{}", g.clip.0, g.layer);
+ let selected = sel_clips.contains(&g.clip) && sel_layers.contains(&g.layer);
+ let fill = if selected {
+ t.row_selected
+ } else if n % 2 == 1 {
+ t.row_alt
+ } else {
+ Color32::TRANSPARENT
+ };
+ let select = |actions: &mut Vec<(String, Value)>| {
+ actions.push(("timeline.select".into(), json!({"clips": [g.clip.0]})));
+ actions.push(("graphics.selectLayer".into(), json!({"clip": g.clip.0, "layers": [g.layer]})));
+ };
+ let frame = egui::Frame::NONE.fill(fill).inner_margin(egui::Margin::symmetric(6, 4)).corner_radius(3.0);
+ let fr = frame.show(ui, |ui| {
+ ui.horizontal_top(|ui| {
+ ui.vertical(|ui| {
+ ui.set_width(92.0);
+ let goto = ui.add(egui::Button::new(egui::RichText::new(tc(g.start)).font(Tokens::mono(11.0)).color(t.hot_text)).frame(false));
+ app.auto.add(&format!("text.graphics.{key}.goto"), goto.rect, "Go to graphic");
+ if goto.clicked() {
+ actions.push(("playhead.set".into(), json!({"time": g.start.0})));
+ select(&mut actions);
+ }
+ let label = match &g.name {
+ Some(name) => format!("{} · {name}", g.track),
+ None => g.track.clone(),
+ };
+ ui.label(egui::RichText::new(label).size(11.0).color(t.text_dim));
+ });
+ ui.vertical(|ui| {
+ let tkey = egui::Id::new(("gfx-text", g.clip.0, g.layer));
+ let mut buf = ui.data(|d| d.get_temp::(tkey)).unwrap_or_else(|| g.text.clone());
+ let resp = ui.add(
+ egui::TextEdit::multiline(&mut buf)
+ .id(tkey.with("te"))
+ .desired_rows(1)
+ .desired_width(ui.available_width())
+ .font(Tokens::ui(12.5))
+ .frame(egui::Frame::NONE),
+ );
+ app.auto.add(&format!("text.graphics.{key}.text"), resp.rect, "Graphic text");
+ if resp.has_focus() {
+ ui.data_mut(|d| d.insert_temp(tkey, buf.clone()));
+ if !selected {
+ select(&mut actions);
+ }
+ } else {
+ ui.data_mut(|d| d.remove::(tkey));
+ }
+ if resp.lost_focus() && buf != g.text {
+ actions.push(("graphics.set".into(), json!({"clip": g.clip.0, "layer": g.layer, "props": {"text": buf}, "time": g.at.0})));
+ }
+ });
+ });
+ });
+ app.auto.add(&format!("text.graphics.{key}.row"), fr.response.rect, &g.text);
+ ui.add_space(2.0);
+ }
+ if shown == 0 {
+ ui.label(
+ egui::RichText::new(if entries.is_empty() {
+ tl!("No text graphics in this sequence. Add text with the Type tool.")
+ } else {
+ tl!("No matching text.")
+ })
+ .color(t.text_faint),
+ );
+ }
+ });
+ run(app, ui, actions);
+}
+
/// Whether a caption is selected, so the Properties panel shows [`caption_properties`].
pub fn caption_selected(app: &FilmcraftApp) -> bool {
app.session.active_sequence().is_some_and(|q| app.session.state.caption_selection.iter().any(|c| q.find_caption(*c).is_some()))
diff --git a/crates/ui-egui/src/panels/timeline.rs b/crates/ui-egui/src/panels/timeline.rs
index c4c369298..a73611886 100644
--- a/crates/ui-egui/src/panels/timeline.rs
+++ b/crates/ui-egui/src/panels/timeline.rs
@@ -294,6 +294,10 @@ pub fn zoom_about(v: &mut TimelineView, factor: f64, anchor_secs: f64, width: f3
v.target_scroll = (anchor_secs - x as f64 / new).max(0.0);
}
+/// How strongly a track's colour label tints its header and its lane.
+const TRACK_HEADER_TINT: f32 = 0.18;
+const TRACK_LANE_TINT: f32 = 0.10;
+
fn label_color(app: &FilmcraftApp, l: filmcraft_project::Label) -> Color32 {
crate::panels::settings::label_color(app, l)
}
@@ -340,7 +344,8 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
v.fit_pending = false;
v.fit_empty = empty.then_some(v.target_pps);
}
- let k = 1.0 - (-dt * 20.0).exp();
+ // eased, or in one step with Settings ▸ Appearance ▸ animations off (#2325)
+ let k = if app.session.prefs.appearance.animations { 1.0 - (-dt * 20.0).exp() } else { 1.0 };
let zooming = (v.pps - v.target_pps).abs() / v.target_pps > 0.001;
// video thumbnails keep the layout of the zoom a gesture or animation started at (#1094)
if zooming || matches!(app.tl.drag, Some(Drag::ZoomBar { mode: 1 | 2, .. })) {
@@ -455,6 +460,10 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
}
let bg = if r.index % 2 == 0 { t.tl_track_bg } else { t.tl_track_bg_alt };
painter.rect_filled(row, 0.0, bg);
+ // a track's colour label tints its lane (#1186)
+ if let Some(l) = seq.track(r.track).and_then(|tr| tr.label) {
+ painter.rect_filled(row, 0.0, label_color(app, l).gamma_multiply(TRACK_LANE_TINT));
+ }
painter.line_segment([pos2(row.min.x, r.rect.max.y - 0.5), pos2(row.max.x, r.rect.max.y - 0.5)], Stroke::new(1.0, t.separator));
// the top video track also gets a line above it
if r.kind == TrackKind::Video && r.index + 1 == nv {
@@ -1258,6 +1267,36 @@ fn draw_headers(app: &mut FilmcraftApp, ui: &mut egui::Ui, seq: &Sequence, rows:
}
let p = ui.painter().with_clip_rect(visible);
p.rect_filled(hrect, 0.0, t.tl_header_bg);
+ // 0. colour label (#1186): a tint over the header, and the strip at its left edge, which
+ // opens the colour menu
+ let strip = Rect::from_min_max(hrect.min, pos2(hrect.min.x + 9.0, hrect.max.y));
+ if let Some(l) = tr.label {
+ let c = label_color(app, l);
+ p.rect_filled(hrect, 0.0, c.gamma_multiply(TRACK_HEADER_TINT));
+ p.rect_filled(Rect::from_min_max(strip.min, pos2(strip.min.x + 5.0, strip.max.y)), 0.0, c);
+ }
+ let cresp = ui.interact(strip.intersect(visible), egui::Id::new(("trackColor", r.track.0)), Sense::click()).on_hover_text(tl!("Track Color"));
+ app.auto.add(&format!("timeline.track.{}{}.color", if r.kind == TrackKind::Video { "V" } else { "A" }, r.index + 1), strip, "Track Color");
+ if cresp.hovered() && tr.label.is_none() {
+ p.rect_filled(Rect::from_min_max(strip.min, pos2(strip.min.x + 5.0, strip.max.y)), 0.0, t.hover);
+ }
+ egui::Popup::menu(&cresp).show(|ui| {
+ let prefix = format!("timeline.track.{}{}.color", if r.kind == TrackKind::Video { "V" } else { "A" }, r.index + 1);
+ let none = ui.selectable_label(tr.label.is_none(), tl!("None"));
+ app.auto.add(&format!("{prefix}.None"), none.rect, "None");
+ if none.clicked() {
+ actions.push(("timeline.setTrack".into(), json!({"track": r.track.0, "label": ""})));
+ ui.close();
+ }
+ // the user's label names and colours, as in Edit ▸ Label
+ let labels = app.session.prefs.labels.clone();
+ for l in filmcraft_project::Label::ALL {
+ if crate::menus::label_choice(ui, &mut app.auto, &labels, l, &prefix).clicked() {
+ actions.push(("timeline.setTrack".into(), json!({"track": r.track.0, "label": l.name()})));
+ ui.close();
+ }
+ }
+ });
p.line_segment([pos2(hrect.min.x, hrect.max.y - 0.5), pos2(hrect.max.x, hrect.max.y - 0.5)], Stroke::new(1.0, t.separator));
if r.kind == TrackKind::Video && r.index + 1 == seq.video_tracks.len() {
p.line_segment([pos2(hrect.min.x, hrect.min.y + 0.5), pos2(hrect.max.x, hrect.min.y + 0.5)], Stroke::new(1.0, t.separator));
diff --git a/crates/ui-egui/src/state.rs b/crates/ui-egui/src/state.rs
index f24e5fa30..e0710236c 100644
--- a/crates/ui-egui/src/state.rs
+++ b/crates/ui-egui/src/state.rs
@@ -436,6 +436,10 @@ pub struct UiState {
pub dock: DockNode,
#[serde(default)]
pub floating: Vec,
+ /// Where each panel closed while floating was ([x, y, width, height]): opening it again
+ /// brings it back there, floating, instead of docked (#1985).
+ #[serde(default)]
+ pub closed_floating: Vec<(PanelKind, [f32; 4])>,
/// Focused panel (blue outline, receives shortcuts).
pub focused: PanelKind,
pub timeline: TimelineView,
@@ -960,6 +964,7 @@ impl Default for UiState {
mode: Mode::Edit,
workspace: "Editing".into(),
floating: vec![],
+ closed_floating: vec![],
dock: crate::dock::workspace("Editing"),
focused: PanelKind::Timeline,
timeline: TimelineView::default(),
diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs
index 21a50012a..36b57165c 100644
--- a/crates/ui-egui/src/theme.rs
+++ b/crates/ui-egui/src/theme.rs
@@ -507,10 +507,14 @@ pub fn apply_visuals(ctx: &egui::Context, t: &Tokens) {
s.text_styles.insert(TextStyle::Small, FontId::new(11.0, FontFamily::Proportional));
s.text_styles.insert(TextStyle::Heading, FontId::new(15.0, FontFamily::Name("semibold".into())));
s.text_styles.insert(TextStyle::Monospace, FontId::new(12.0, FontFamily::Monospace));
- s.animation_time = 0.12;
+ s.animation_time = ANIMATION_TIME;
});
}
+/// How long egui's fades and slides take (menus, collapsing sections, tooltips); 0 when
+/// Settings ▸ Appearance ▸ "Animate zoom, scrolling and menus" is off (#2325).
+pub const ANIMATION_TIME: f32 = 0.12;
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/crates/ui-egui/tests/graphics_handles_ui.rs b/crates/ui-egui/tests/graphics_handles_ui.rs
index 5a7090fdd..f3c03fb51 100644
--- a/crates/ui-egui/tests/graphics_handles_ui.rs
+++ b/crates/ui-egui/tests/graphics_handles_ui.rs
@@ -357,6 +357,26 @@ fn text_committed_by_an_input_method_is_typed_on_the_monitor() {
assert_eq!(list["layers"][0]["text"], "A你好");
}
+/// #2430: a click (no drag) in the text being edited on the monitor puts the caret there; before,
+/// only a press that moved a little did, and typing went on at the end.
+#[test]
+fn a_click_in_the_edited_text_moves_the_caret() {
+ let mut d = Driver::new();
+ d.ok("ui.set", json!({"tool": "Type"}));
+ d.frames(3);
+ let pic = d.rect("program.picture");
+ d.ok("ui.click", json!({"x": pic[0] + pic[2] * 0.3, "y": pic[1] + pic[3] * 0.2}));
+ d.ok("ui.type", json!({"text": "Title"}));
+ d.frames(2);
+ let text = d.rect("program.textEdit");
+ // just inside the first letter: the caret goes before it
+ d.ok("ui.click", json!({"x": text[0] + 1.0, "y": text[1] + text[3] / 2.0}));
+ d.frames(2);
+ d.ok("ui.type", json!({"text": "X"}));
+ d.frames(2);
+ assert_eq!(d.exec("graphics.list", json!({}))["layers"][0]["text"], "XTitle");
+}
+
#[test]
fn text_properties_switches_between_point_and_paragraph_text() {
let mut d = Driver::new();
diff --git a/crates/ui-egui/tests/graphics_ui.rs b/crates/ui-egui/tests/graphics_ui.rs
index c7aa5138e..fffa7a1d9 100644
--- a/crates/ui-egui/tests/graphics_ui.rs
+++ b/crates/ui-egui/tests/graphics_ui.rs
@@ -230,3 +230,171 @@ fn shadow_color_drag_is_one_undo_step() {
d.exec("edit.undo", json!({}));
assert_eq!(color(&mut d), before, "one undo restores the original color");
}
+
+/// Character ranges use setCharStyle, but must share the same one-gesture undo rule as a layer.
+#[test]
+fn selected_character_size_drag_is_one_undo_step() {
+ let mut d = Driver::demo();
+ d.ok("ui.set", json!({"workspace":"Captions and Graphics","tool":"Type"}));
+ d.exec("playhead.set", json!({"seconds":2}));
+ d.frames(3);
+ let p = d.rect("program.picture");
+ d.ok("ui.click", json!({"x":p[0]+p[2]*0.2,"y":p[1]+p[3]*0.35}));
+ d.ok("ui.type", json!({"text":"Undo drag test"}));
+ d.ok("ui.key", json!({"key":"Cmd+A"}));
+ d.frames(3);
+ let before = d.harness.state().session.project.clone();
+ let n = d.harness.state().session.history.undo.len();
+ let r = d.rect("graphics.prop.size");
+ d.ok("ui.drag", json!({"from":{"x":r[0]+r[2]/2.0,"y":r[1]+r[3]/2.0},"to":{"x":r[0]+r[2]/2.0+80.0,"y":r[1]+r[3]/2.0},"steps":8}));
+ d.frames(3);
+ assert_eq!(d.harness.state().session.history.undo.len(), n + 1);
+ let after = d.harness.state().session.project.clone();
+ assert_ne!(*after, *before);
+ d.exec("edit.undo", json!({}));
+ assert_eq!(*d.harness.state().session.project, *before);
+ d.exec("edit.redo", json!({}));
+ assert_eq!(*d.harness.state().session.project, *after);
+}
+
+/// The Properties panel's stopwatches animate a layer property (#2358): Tracking (letter
+/// spacing) gets keyframes from the Essential Graphics panel itself, a change at another time
+/// adds a keyframe there instead of changing the value everywhere, and the stopwatch turns
+/// keyframing off again.
+#[test]
+fn the_tracking_stopwatch_animates_letter_spacing() {
+ let mut d = Driver::demo();
+ d.ok("ui.set", json!({"workspace": "Captions and Graphics"}));
+ d.exec("playhead.set", json!({"seconds": 0.0}));
+ let r = d.exec("graphics.newText", json!({"text": "Title", "seconds": 4}));
+ let clip = r["clip"].as_u64().unwrap();
+ d.exec("graphics.selectLayer", json!({"clip": clip, "layers": [0]}));
+ d.frames(4);
+ for _ in 0..20 {
+ if d.rect("graphics.prop.tracking")[1] < 800.0 {
+ break;
+ }
+ d.ok("ui.scroll", json!({"id": "graphics.prop.scale", "dy": -200.0}));
+ d.frames(2);
+ }
+ let keys = |d: &mut Driver| -> Vec<(i64, f64)> {
+ let s = &d.harness.state().session;
+ let (_, it) = s.active_sequence().unwrap().find_item(filmcraft_project::ClipId(clip)).unwrap();
+ let e = it.effects.iter().find(|e| e.effect == "graphic_text").unwrap();
+ e.params.get("tracking").map(|p| p.keyframes.iter().map(|k| (k.time.0, k.value.as_f64().unwrap())).collect()).unwrap_or_default()
+ };
+ assert!(keys(&mut d).is_empty());
+ d.ok("ui.click", json!({"id": "graphics.prop.tracking.stopwatch"}));
+ d.frames(2);
+ assert_eq!(keys(&mut d).len(), 1, "the stopwatch sets a keyframe at the playhead");
+ // two seconds later, drag the Tracking number: a second keyframe, the first stays
+ d.exec("playhead.set", json!({"seconds": 2.0}));
+ d.frames(2);
+ let n = d.rect("graphics.prop.tracking");
+ let (cx, cy) = (n[0] + n[2] / 2.0, n[1] + n[3] / 2.0);
+ d.ok("ui.drag", json!({"from": {"x": cx, "y": cy}, "to": {"x": cx + 60.0, "y": cy}, "steps": 6}));
+ d.frames(4);
+ let k = keys(&mut d);
+ assert_eq!(k.len(), 2, "{k:?}");
+ // the clip starts at 0, where the first keyframe was set, so the second one sits at the playhead
+ let playhead = d.harness.state().session.playhead().0;
+ assert_eq!((k[0].0, k[1].0), (0, playhead), "the keyframes are where the playhead was: {k:?}");
+ assert_eq!(k[0].1, 0.0, "the first keyframe keeps its value: {k:?}");
+ assert!(k[1].1 > 10.0, "the new keyframe has the dragged value: {k:?}");
+ // letter spacing now animates: halfway between the keyframes the value is in between
+ let mid = {
+ let s = &d.harness.state().session;
+ let (_, it) = s.active_sequence().unwrap().find_item(filmcraft_project::ClipId(clip)).unwrap();
+ let e = it.effects.iter().find(|e| e.effect == "graphic_text").unwrap();
+ e.param("tracking").unwrap().value_at(filmcraft_time::Tick((k[0].0 + k[1].0) / 2)).as_f64().unwrap()
+ };
+ assert!(mid > 0.0 && mid < k[1].1, "{mid} between 0 and {}", k[1].1);
+ d.ok("ui.click", json!({"id": "graphics.prop.tracking.stopwatch"}));
+ d.frames(2);
+ assert!(keys(&mut d).is_empty(), "the stopwatch turns keyframing off");
+ d.shot("tracking-stopwatch");
+}
+
+/// Text panel ▸ Graphics (#1487): the text of every text layer in the sequence, in timeline
+/// order, searchable; the timecode goes to the clip and selects the layer, and the text edits in
+/// place as one undo step.
+#[test]
+fn the_text_panels_graphics_tab_lists_and_edits_graphic_text() {
+ let mut d = Driver::demo();
+ d.ok("ui.set", json!({"workspace": "Captions and Graphics"}));
+ let mut clips = Vec::new();
+ for (sec, text) in [(6.0, "Closing credits"), (1.0, "Opening title")] {
+ d.exec("playhead.set", json!({"seconds": sec}));
+ let r = d.exec("graphics.newText", json!({"text": text, "seconds": 2}));
+ clips.push(r["clip"].as_u64().unwrap());
+ }
+ let (credits, title) = (clips[0], clips[1]);
+ d.exec("playhead.set", json!({"seconds": 10.0}));
+ d.ok("ui.click", json!({"id": "text.tab.Graphics"}));
+ d.frames(3);
+ let rows = |d: &mut Driver| -> Vec {
+ let v = d.ok("ui.elements", json!({"prefix": "text.graphics."}));
+ v.as_array().unwrap().iter().filter(|e| e["id"].as_str().unwrap().ends_with(".row")).map(|e| e["label"].as_str().unwrap_or("").to_string()).collect()
+ };
+ assert_eq!(rows(&mut d), ["Opening title", "Closing credits"], "in timeline order");
+ // search
+ d.ok("ui.click", json!({"id": "text.graphics.search"}));
+ d.ok("ui.type", json!({"text": "CRED"}));
+ d.frames(3);
+ assert_eq!(rows(&mut d), ["Closing credits"]);
+ d.ok("ui.key", json!({"key": "A", "command": true}));
+ d.ok("ui.key", json!({"key": "Backspace"}));
+ d.frames(3);
+ assert_eq!(rows(&mut d).len(), 2);
+ // the timecode goes to the clip and selects its layer
+ d.ok("ui.click", json!({"id": format!("text.graphics.{credits}.0.goto")}));
+ d.frames(3);
+ let start = d.harness.state().session.active_sequence().unwrap().find_item(filmcraft_project::ClipId(credits)).unwrap().1.start;
+ assert_eq!(d.harness.state().session.playhead(), start);
+ assert_eq!(d.harness.state().session.state.selection, vec![filmcraft_project::ClipId(credits)]);
+ assert_eq!(d.harness.state().session.state.graphic_layers, vec![0]);
+ // edit the title's text in place
+ let undo0 = d.exec("history.list", json!({}))["undo"].as_array().unwrap().len();
+ d.ok("ui.click", json!({"id": format!("text.graphics.{title}.0.text")}));
+ d.ok("ui.key", json!({"key": "A", "command": true}));
+ d.ok("ui.type", json!({"text": "Night Drive"}));
+ d.ok("ui.click", json!({"id": "text.graphics.search"}));
+ d.frames(3);
+ let text = text_param(&mut d, title, "text");
+ assert_eq!(text, Some(filmcraft_project::ParamValue::Text("Night Drive".into())));
+ assert_eq!(d.exec("history.list", json!({}))["undo"].as_array().unwrap().len(), undo0 + 1, "one undo step");
+ assert_eq!(rows(&mut d), ["Night Drive", "Closing credits"]);
+ d.shot("text-panel-graphics");
+}
+
+/// Keyframed text: the Graphics tab shows a clip's text at the clip's start when the playhead is
+/// past the clip, and an edit is written there (not at the clip's last frame), so the value shown
+/// is the one that changes.
+#[test]
+fn a_graphics_tab_edit_writes_keyframed_text_where_it_is_shown() {
+ let mut d = Driver::demo();
+ d.ok("ui.set", json!({"workspace": "Captions and Graphics"}));
+ d.exec("playhead.set", json!({"seconds": 1.0}));
+ let clip = d.exec("graphics.newText", json!({"text": "Start", "seconds": 2}))["clip"].as_u64().unwrap();
+ let it = d.harness.state().session.active_sequence().unwrap().find_item(filmcraft_project::ClipId(clip)).unwrap().1.clone();
+ // animate the text: "Start" at the clip's start, "End" near its end
+ d.exec("effects.toggleAnimation", json!({"clip": clip, "effect": "graphic_text", "param": "text"}));
+ let late = it.start.0 + (it.duration.0 * 9) / 10;
+ d.exec("graphics.set", json!({"clip": clip, "layer": 0, "props": {"text": "End"}, "time": late}));
+ // the playhead past the clip: the row shows the start's text
+ d.exec("playhead.set", json!({"seconds": 10.0}));
+ d.ok("ui.click", json!({"id": "text.tab.Graphics"}));
+ d.frames(3);
+ d.ok("ui.click", json!({"id": format!("text.graphics.{clip}.0.text")}));
+ d.ok("ui.key", json!({"key": "A", "command": true}));
+ d.ok("ui.type", json!({"text": "Edited"}));
+ d.ok("ui.click", json!({"id": "text.graphics.search"}));
+ d.frames(3);
+ let at = |d: &mut Driver, t: i64| {
+ let it = d.harness.state().session.active_sequence().unwrap().find_item(filmcraft_project::ClipId(clip)).unwrap().1.clone();
+ let mt = it.effect_time_at(filmcraft_time::Tick(t));
+ it.effects.iter().find(|e| e.effect == "graphic_text").unwrap().param("text").unwrap().value_at(mt)
+ };
+ assert_eq!(at(&mut d, it.start.0), filmcraft_project::ParamValue::Text("Edited".into()), "the shown (start) value changed");
+ assert_eq!(at(&mut d, late), filmcraft_project::ParamValue::Text("End".into()), "the end keeps its own");
+}
diff --git a/crates/ui-egui/tests/interface_zoom_ui.rs b/crates/ui-egui/tests/interface_zoom_ui.rs
new file mode 100644
index 000000000..2908a0017
--- /dev/null
+++ b/crates/ui-egui/tests/interface_zoom_ui.rs
@@ -0,0 +1,96 @@
+//! Headless UI tests of the interface zoom (#2253).
+
+use std::sync::mpsc::{Sender, channel};
+
+use egui_kittest::Harness;
+use filmcraft_engine::Session;
+use filmcraft_ui_egui::FilmcraftApp;
+use filmcraft_ui_egui::control::ControlRequest;
+use serde_json::{Value, json};
+
+struct Driver {
+ harness: Harness<'static, FilmcraftApp>,
+ tx: Sender,
+}
+
+impl Driver {
+ fn demo() -> Self {
+ let mut session = Session::default();
+ session.execute("file.openDemoProject", json!({})).expect("demo project");
+ let (tx, rx) = channel();
+ let app = FilmcraftApp::new(session).with_control(rx);
+ let harness = Harness::builder().with_size(egui::vec2(1600.0, 980.0)).with_step_dt(1.0 / 60.0).with_max_steps(10_000).build_eframe(move |_cc| app);
+ let mut d = Driver { harness, tx };
+ d.frames(4);
+ d
+ }
+
+ fn frames(&mut self, n: usize) {
+ for _ in 0..n {
+ let ctx = self.harness.ctx.clone();
+ let mut raw = std::mem::take(self.harness.input_mut());
+ eframe::App::raw_input_hook(self.harness.state_mut(), &ctx, &mut raw);
+ *self.harness.input_mut() = raw;
+ self.harness.step();
+ }
+ }
+
+ fn ok(&mut self, method: &str, params: Value) -> Value {
+ let (req, reply) = ControlRequest::new(method, params.clone());
+ self.tx.send(req).unwrap();
+ for _ in 0..600 {
+ self.frames(1);
+ if let Ok(v) = reply.try_recv() {
+ assert_eq!(v["ok"], json!(true), "{method} {params} failed: {v}");
+ return v["result"].clone();
+ }
+ }
+ panic!("no reply to {method} {params}");
+ }
+
+ fn click(&mut self, id: &str) {
+ self.ok("ui.click", json!({"id": id}));
+ self.frames(2);
+ }
+
+ fn app(&mut self) -> &mut FilmcraftApp {
+ self.harness.state_mut()
+ }
+
+ /// One key press with `modifiers`, as the window reports it.
+ fn press(&mut self, key: egui::Key, modifiers: egui::Modifiers) {
+ let events = &mut self.harness.input_mut().events;
+ events.push(egui::Event::ModifiersChanged(modifiers));
+ for pressed in [true, false] {
+ events.push(egui::Event::Key { key, physical_key: None, pressed, repeat: false, modifiers });
+ }
+ events.push(egui::Event::ModifiersChanged(egui::Modifiers::NONE));
+ self.frames(3);
+ }
+}
+
+/// #2253: with the Timeline focused, Ctrl+= and Ctrl+- are its track-height keys, but Ctrl+Plus
+/// (the `+` key, or Shift+=) fell through to egui and scaled the whole interface, which the taken
+/// Ctrl+- and Ctrl+0 could not undo. `+` now goes where `=` goes, and View ▸ Reset Interface Zoom
+/// gives the configured scale back.
+#[test]
+fn ctrl_plus_does_what_ctrl_equals_does_and_the_interface_zoom_can_be_reset() {
+ let mut d = Driver::demo();
+ let clip = d.app().session.active_sequence().unwrap().video_tracks[0].items[0].id.0;
+ d.click(&format!("timeline.clip.{clip}"));
+ assert_eq!(d.app().ui.focused, filmcraft_ui_egui::dock::PanelKind::Timeline);
+ let zoom = d.harness.ctx.zoom_factor();
+ let height = d.app().ui.timeline.video_track_h;
+ d.press(egui::Key::Plus, egui::Modifiers::COMMAND);
+ assert_eq!(d.harness.ctx.zoom_factor(), zoom, "the interface keeps its scale");
+ assert!(d.app().ui.timeline.video_track_h > height, "Ctrl+Plus makes the video tracks taller, as Ctrl+= does");
+
+ // however it got scaled, View ▸ Reset Interface Zoom brings it back
+ d.harness.ctx.set_zoom_factor(1.75);
+ d.frames(2);
+ assert_eq!(d.harness.ctx.zoom_factor(), 1.75);
+ let r = d.ok("ui.menu.invoke", json!({"id": "view.resetInterfaceZoom"}));
+ assert_eq!(r["zoom"], json!(1.0), "the reply says the zoom it set: {r}");
+ d.frames(2);
+ assert_eq!(d.harness.ctx.zoom_factor(), 1.0);
+}
diff --git a/crates/ui-egui/tests/keyframes_ui.rs b/crates/ui-egui/tests/keyframes_ui.rs
index d0549a015..a4cb06c07 100644
--- a/crates/ui-egui/tests/keyframes_ui.rs
+++ b/crates/ui-egui/tests/keyframes_ui.rs
@@ -708,3 +708,22 @@ fn mask_keyframe_menus_preserve_the_effect_and_other_masks() {
assert_eq!(effect(&d), before);
}
}
+
+/// #2328: a line separates the fixed effects (Motion, Opacity, Time Remapping) from the effects
+/// added from the library; without added effects there is none.
+#[test]
+fn a_line_separates_added_effects_from_the_fixed_ones() {
+ let (mut d, clip) = Driver::demo();
+ assert!(d.find("effectControls.addedEffects.video").is_none(), "only fixed effects: no line");
+ d.exec("effects.apply", json!({"clips": [clip.id], "effect": "gaussian_blur"}));
+ d.exec("effects.apply", json!({"clips": [clip.id], "effect": "tint"}));
+ let line = d.rect("effectControls.addedEffects.video");
+ let opacity = d.rect("effectControls.effect.opacity");
+ let blur = d.rect("effectControls.effect.gaussian_blur");
+ let tint = d.rect("effectControls.effect.tint");
+ assert!(
+ opacity[1] < line[1] && (line[1] + line[3] / 2.0 - blur[1]).abs() <= 0.5,
+ "on the edge between the fixed and the added effects: {opacity:?} {line:?} {blur:?}"
+ );
+ assert!(tint[1] > blur[1], "one line, above all the added effects");
+}
diff --git a/crates/ui-egui/tests/multicam_ui.rs b/crates/ui-egui/tests/multicam_ui.rs
index 3b84105ee..9bd378b94 100644
--- a/crates/ui-egui/tests/multicam_ui.rs
+++ b/crates/ui-egui/tests/multicam_ui.rs
@@ -389,3 +389,28 @@ fn multicam_view_pages_beyond_sixteen_angles_and_edit_cameras() {
assert!(!mc.cameras[1].enabled);
assert_eq!(d.exec("multicam.grid", json!({}))["angles"], 19);
}
+
+/// #1362: with nothing selected in the Project panel, Create Multi-Camera Source Sequence works on
+/// the clips selected in the Timeline.
+#[test]
+fn create_multicam_from_clips_selected_in_the_timeline() {
+ let (s, items) = session();
+ let mut d = Driver::new(s);
+ for (k, item) in items.iter().enumerate() {
+ d.exec("source.open", json!({"item": item}));
+ d.exec("playhead.set", json!({"frame": k as i64 * 96}));
+ d.exec("source.overwrite", json!({}));
+ }
+ let clips: Vec = d.app().session.active_sequence().unwrap().video_tracks[0].items.iter().map(|c| c.id.0).collect();
+ assert_eq!(clips.len(), 4);
+ d.exec("project.select", json!({"items": []}));
+ d.exec("timeline.select", json!({"clips": clips}));
+ d.ok("ui.menu.invoke", json!({"id": "clip.createMulticam"}));
+ d.frames(3);
+ assert_eq!(d.app().ui.sync_dialog.as_ref().map(|x| x.items.clone()), Some(items.clone()), "the dialog takes the Timeline clips' media");
+ d.click("mcam.method.in");
+ d.click("mcam.ok");
+ assert!(d.app().ui.sync_dialog.is_none(), "dialog closed: {}", d.app().ui.status);
+ let src = d.app().session.state.project_selection[0];
+ assert_eq!(d.app().session.project.sequence(src).unwrap().multicam.clone().unwrap().cameras.len(), 4);
+}
diff --git a/crates/ui-egui/tests/panels_ui.rs b/crates/ui-egui/tests/panels_ui.rs
index acc672a35..483bee1c9 100644
--- a/crates/ui-egui/tests/panels_ui.rs
+++ b/crates/ui-egui/tests/panels_ui.rs
@@ -744,3 +744,40 @@ fn middle_closing_an_inactive_project_tab_keeps_the_inspector_target() {
let source = d.app().ui.panels.inspector_source;
assert_eq!(d.label("info.item"), name, "closing a tab must not select its stale item; focused={focused:?}, source={source:?}");
}
+
+/// #2329: in the Effects panel what a folder holds is indented under it: an effect's label starts
+/// right of its sub-folder's, a sub-folder's right of its top folder's, and the same for presets
+/// and Lumetri presets.
+#[test]
+fn effects_are_indented_under_their_folders() {
+ fn text_x(d: &mut Driver, text: &str) -> f32 {
+ fn find(shapes: &[egui::Shape], text: &str) -> Option {
+ shapes.iter().find_map(|s| match s {
+ egui::Shape::Text(t) if t.galley.text() == text => Some(t.pos.x),
+ egui::Shape::Vec(v) => find(v, text),
+ _ => None,
+ })
+ }
+ let shapes: Vec = d.harness.output().shapes.iter().map(|c| c.shape.clone()).collect();
+ find(&shapes, text).unwrap_or_else(|| panic!("`{text}` is not drawn"))
+ }
+ let mut d = Driver::demo();
+ d.ok("ui.panel.show", json!({"panel": "Effects"}));
+ d.frames(3);
+ for folder in ["Video Effects", "Video Effects/Blur & Sharpen", "Presets", "Lumetri Presets", "Lumetri Presets/Monochrome"] {
+ d.click(&format!("effects.folder.{folder}"));
+ }
+ d.frames(2);
+ let preset = d.app().session.presets.all()[0].name.clone();
+ let lumetri = filmcraft_render::lumetri_presets::presets().into_iter().find(|p| p.folder == "Monochrome").unwrap().name;
+ for (outer, inner) in [
+ ("Video Effects", "Blur & Sharpen"),
+ ("Blur & Sharpen", "Gaussian Blur"),
+ ("Presets", preset.as_str()),
+ ("Lumetri Presets", "Monochrome"),
+ ("Monochrome", lumetri),
+ ] {
+ let (a, b) = (text_x(&mut d, outer), text_x(&mut d, inner));
+ assert!(b >= a + 12.0, "`{inner}` ({b}) is not indented under `{outer}` ({a})");
+ }
+}
diff --git a/crates/ui-egui/tests/perf_ui.rs b/crates/ui-egui/tests/perf_ui.rs
index 5b9d6c845..9b392a239 100644
--- a/crates/ui-egui/tests/perf_ui.rs
+++ b/crates/ui-egui/tests/perf_ui.rs
@@ -190,3 +190,32 @@ fn a_newer_revision_keeps_the_frame_being_rendered() {
d.ready(key(9002));
d.ready(key(9001));
}
+
+/// #1682: thumbnail textures (timeline tiles, hover scrubs) are capped instead of one being kept
+/// for every frame ever shown.
+#[test]
+fn thumbnail_textures_are_capped() {
+ let mut d = Driver::demo();
+ let ctx = d.harness.ctx.clone();
+ let item = {
+ let p = &d.harness.state().session.project;
+ p.items.values().find(|i| i.as_media().is_some_and(|m| m.info.video.is_some())).expect("a video item").id
+ };
+ let rate = d.harness.state().session.project.item(item).unwrap().frame_rate();
+ // 800 distinct frames, 100 per UI pass: request, wait until rendered, then make the textures
+ for chunk in 0..8 {
+ let frames: Vec = (chunk * 100..chunk * 100 + 100).collect();
+ for &f in &frames {
+ d.harness.state_mut().thumbnail(&ctx, item, rate.tick_of(f), 32);
+ }
+ for _ in 0..2000 {
+ if frames.iter().all(|&f| d.harness.state_mut().thumbnail(&ctx, item, rate.tick_of(f), 32).is_some()) {
+ break;
+ }
+ std::thread::sleep(std::time::Duration::from_millis(5));
+ }
+ d.frames(1);
+ }
+ let n = d.harness.state().thumbnail_textures();
+ assert!((100..=512).contains(&n), "{n} thumbnail textures");
+}
diff --git a/crates/ui-egui/tests/shared_docking_ui.rs b/crates/ui-egui/tests/shared_docking_ui.rs
index 3df87b903..7d087bcb4 100644
--- a/crates/ui-egui/tests/shared_docking_ui.rs
+++ b/crates/ui-egui/tests/shared_docking_ui.rs
@@ -559,3 +559,54 @@ fn narration_selection_reveals_covered_floating_tts_once_without_editing_the_pro
assert_eq!(h.state().ui.tts, draft);
assert!(std::sync::Arc::ptr_eq(&project, &h.state().session.project));
}
+
+/// #1985: a panel closed while floating came back docked when opened again from the Window menu;
+/// it now floats again where it was. Closed while docked, it opens docked as before.
+#[test]
+fn a_panel_closed_while_floating_reopens_floating_where_it_was() {
+ let mut app = FilmcraftApp::new(Session::default());
+ let ctx = egui::Context::default();
+ menus::invoke(&mut app, &ctx, "window.floatPanel", json!({"panel": "Info", "rect": [45, 65, 420, 320]})).unwrap();
+ let rect = app.ui.floating.iter().find(|g| g.panels.contains(&PanelKind::Info)).unwrap().rect;
+ menus::invoke(&mut app, &ctx, "window.closePanel", json!({"panel": "Info"})).unwrap();
+ assert!(!app.ui.dock.contains(PanelKind::Info) && !app.ui.floating.iter().any(|g| g.panels.contains(&PanelKind::Info)));
+ menus::invoke(&mut app, &ctx, &menus::panel_command_id(PanelKind::Info), json!({})).unwrap();
+ let back = app.ui.floating.iter().find(|g| g.panels.contains(&PanelKind::Info)).expect("Info floats again");
+ assert_eq!(back.rect, rect, "where it was");
+ assert!(!app.ui.dock.contains(PanelKind::Info));
+ // docked, then closed: it opens docked
+ menus::invoke(&mut app, &ctx, "window.dockPanel", json!({"panel": "Info", "anchor": "Project"})).unwrap();
+ menus::invoke(&mut app, &ctx, "window.closePanel", json!({"panel": "Info"})).unwrap();
+ menus::invoke(&mut app, &ctx, &menus::panel_command_id(PanelKind::Info), json!({})).unwrap();
+ assert!(app.ui.dock.contains(PanelKind::Info));
+ assert!(!app.ui.floating.iter().any(|g| g.panels.contains(&PanelKind::Info)));
+ // the Timeline too, though reopening it first puts it back in its own place in the dock
+ menus::invoke(&mut app, &ctx, "window.floatPanel", json!({"panel": "Timeline", "rect": [60, 80, 700, 300]})).unwrap();
+ let rect = app.ui.floating.iter().find(|g| g.panels.contains(&PanelKind::Timeline)).unwrap().rect;
+ menus::invoke(&mut app, &ctx, "window.closePanel", json!({"panel": "Timeline"})).unwrap();
+ menus::invoke(&mut app, &ctx, &menus::panel_command_id(PanelKind::Timeline), json!({})).unwrap();
+ let back = app.ui.floating.iter().find(|g| g.panels.contains(&PanelKind::Timeline)).expect("the Timeline floats again");
+ assert_eq!(back.rect, rect);
+ assert!(!app.ui.dock.contains(PanelKind::Timeline));
+
+ // with nothing else docked, a reopened panel has to stay docked (the workspace keeps one
+ // docked panel); its floating place is kept, not lost (#2482 review)
+ let mut app = FilmcraftApp::new(Session::default());
+ menus::invoke(&mut app, &ctx, "window.floatPanel", json!({"panel": "Info", "rect": [45, 65, 420, 320]})).unwrap();
+ let rect = app.ui.floating.iter().find(|g| g.panels.contains(&PanelKind::Info)).unwrap().rect;
+ for _ in 0..64 {
+ let Some(p) = PanelKind::ALL.iter().copied().find(|p| app.ui.dock.contains(*p)) else { break };
+ if menus::invoke(&mut app, &ctx, "window.closePanel", json!({"panel": p.id()})).is_err() {
+ break;
+ }
+ }
+ let docked = PanelKind::ALL.iter().filter(|p| app.ui.dock.contains(**p)).count();
+ if docked > 0 {
+ eprintln!("SKIPPED: the dock cannot be emptied ({docked} panels stay)");
+ return;
+ }
+ menus::invoke(&mut app, &ctx, "window.closePanel", json!({"panel": "Info"})).unwrap();
+ menus::invoke(&mut app, &ctx, &menus::panel_command_id(PanelKind::Info), json!({})).unwrap();
+ assert!(app.ui.dock.contains(PanelKind::Info), "the only panel stays docked");
+ assert!(app.ui.closed_floating.iter().any(|(p, r)| *p == PanelKind::Info && *r == rect), "{:?}", app.ui.closed_floating);
+}
diff --git a/crates/ui-egui/tests/timeline_scroll_ui.rs b/crates/ui-egui/tests/timeline_scroll_ui.rs
index 7587ef14a..aa9dec2b1 100644
--- a/crates/ui-egui/tests/timeline_scroll_ui.rs
+++ b/crates/ui-egui/tests/timeline_scroll_ui.rs
@@ -342,3 +342,33 @@ fn repeated_home_and_end_keys_reveal_a_playhead_already_at_the_endpoint() {
fn repeated_start_and_end_commands_reveal_a_playhead_already_at_the_endpoint() {
repeated_endpoint_navigation_reveals_the_same_playhead(false);
}
+
+/// #2325: Settings ▸ Appearance ▸ "Animate zoom, scrolling and menus" off makes a zoom and a
+/// scroll land in one frame, and egui's fades (menus, collapsing sections, tooltips) instant.
+#[test]
+fn turning_animations_off_zooms_and_scrolls_in_one_step() {
+ let mut d = Driver::tall();
+ let animation_time = |d: &mut Driver| d.harness.ctx.global_style().animation_time;
+ assert!(animation_time(&mut d) > 0.0, "animated by default");
+ // animated: one frame later the zoom is on its way, not there
+ let v = &mut d.app().ui.timeline;
+ v.target_pps = 200.0;
+ v.target_scroll = 8.0;
+ d.frames(1);
+ let v = &d.app().ui.timeline;
+ assert!(v.pps > 50.0 && v.pps < 200.0 && v.scroll < 8.0, "eased: {} {}", v.pps, v.scroll);
+ assert_eq!(d.view(), (8.0, 200.0, 0.0, 0.0));
+ d.exec("prefs.set", json!({"key": "appearance.animations", "value": false}));
+ d.frames(2);
+ assert_eq!(animation_time(&mut d), 0.0);
+ let v = &mut d.app().ui.timeline;
+ v.target_pps = 50.0;
+ v.target_scroll = 3.0;
+ d.frames(1);
+ let v = &d.app().ui.timeline;
+ assert_eq!((v.pps, v.scroll), (50.0, 3.0), "in one step");
+ // and back on
+ d.exec("prefs.set", json!({"key": "appearance.animations", "value": true}));
+ d.frames(2);
+ assert!(animation_time(&mut d) > 0.0);
+}
diff --git a/crates/ui-egui/tests/track_color_ui.rs b/crates/ui-egui/tests/track_color_ui.rs
new file mode 100644
index 000000000..f20d76899
--- /dev/null
+++ b/crates/ui-egui/tests/track_color_ui.rs
@@ -0,0 +1,161 @@
+//! Headless UI test of track colour labels (#1186): the strip at the left edge of a track header
+//! opens the colour menu; the label tints the header and the lane and is an undoable track setting.
+//!
+//! Set `FILMCRAFT_UI_SNAPSHOT_DIR=` to also render offscreen with wgpu and write `track-color-*.png`.
+
+#![allow(dead_code)]
+
+use std::sync::mpsc::{Sender, channel};
+
+use egui_kittest::Harness;
+use filmcraft_engine::Session;
+use filmcraft_ui_egui::FilmcraftApp;
+use filmcraft_ui_egui::control::ControlRequest;
+use serde_json::{Value, json};
+
+struct Driver {
+ harness: Harness<'static, FilmcraftApp>,
+ tx: Sender,
+ snapshots: Option,
+}
+
+impl Driver {
+ fn demo() -> Self {
+ let mut session = Session::default();
+ session.execute("file.openDemoProject", json!({})).expect("demo project");
+ let (tx, rx) = channel();
+ let app = FilmcraftApp::new(session).with_control(rx);
+ let snapshots = std::env::var_os("FILMCRAFT_UI_SNAPSHOT_DIR").map(std::path::PathBuf::from);
+ let mut b = Harness::builder().with_size(egui::vec2(1600.0, 980.0)).with_max_steps(10_000);
+ if snapshots.is_some() {
+ b = b.wgpu();
+ }
+ let harness = b.build_eframe(move |_cc| app);
+ let mut d = Driver { harness, tx, snapshots };
+ d.frames(4);
+ d
+ }
+
+ fn frames(&mut self, n: usize) {
+ for _ in 0..n {
+ let ctx = self.harness.ctx.clone();
+ let mut raw = std::mem::take(self.harness.input_mut());
+ eframe::App::raw_input_hook(self.harness.state_mut(), &ctx, &mut raw);
+ *self.harness.input_mut() = raw;
+ self.harness.step();
+ }
+ }
+
+ fn call(&mut self, method: &str, params: Value) -> Value {
+ let (req, reply) = ControlRequest::new(method, params.clone());
+ self.tx.send(req).unwrap();
+ for _ in 0..600 {
+ self.frames(1);
+ if let Ok(v) = reply.try_recv() {
+ return v;
+ }
+ }
+ panic!("no reply to {method} {params}");
+ }
+
+ fn ok(&mut self, method: &str, params: Value) -> Value {
+ let v = self.call(method, params.clone());
+ assert_eq!(v["ok"], json!(true), "{method} {params} failed: {v}");
+ v["result"].clone()
+ }
+
+ fn exec(&mut self, command: &str, params: Value) -> Value {
+ self.ok("engine.execute", json!({"command": command, "params": params}))
+ }
+
+ fn click(&mut self, id: &str) {
+ self.ok("ui.click", json!({"id": id}));
+ self.frames(2);
+ }
+
+ fn element(&mut self, id: &str) -> Option<[f32; 4]> {
+ let v = self.ok("ui.elements", json!({"prefix": id}));
+ v.as_array()?.iter().find(|e| e["id"] == id).map(|e| {
+ let r = &e["rect"];
+ [r[0].as_f64().unwrap() as f32, r[1].as_f64().unwrap() as f32, r[2].as_f64().unwrap() as f32, r[3].as_f64().unwrap() as f32]
+ })
+ }
+
+ fn ids(&mut self, prefix: &str) -> Vec {
+ let v = self.ok("ui.elements", json!({"prefix": prefix}));
+ v.as_array().unwrap().iter().filter_map(|e| e["id"].as_str().map(str::to_string)).collect()
+ }
+
+ /// Offscreen render of the window (or the bounding box of the elements under `prefix`).
+ fn snapshot(&mut self, name: &str, prefix: Option<&str>) {
+ let Some(dir) = self.snapshots.clone() else { return };
+ let crop = prefix.map(|p| {
+ let v = self.ok("ui.elements", json!({"prefix": p}));
+ let mut bb = [f32::MAX, f32::MAX, f32::MIN, f32::MIN];
+ for e in v.as_array().unwrap() {
+ let r = &e["rect"];
+ let (x, y, w, h) = (r[0].as_f64().unwrap() as f32, r[1].as_f64().unwrap() as f32, r[2].as_f64().unwrap() as f32, r[3].as_f64().unwrap() as f32);
+ bb = [bb[0].min(x), bb[1].min(y), bb[2].max(x + w), bb[3].max(y + h)];
+ }
+ bb
+ });
+ self.frames(2);
+ let img = match self.harness.render() {
+ Ok(i) => i,
+ Err(e) => {
+ eprintln!("snapshot {name} skipped: {e}");
+ return;
+ }
+ };
+ let ppp = img.width() as f32 / 1600.0;
+ let img = match crop {
+ Some(bb) => {
+ let x0 = ((bb[0] - 24.0) * ppp).max(0.0) as u32;
+ let y0 = ((bb[1] - 30.0) * ppp).max(0.0) as u32;
+ let x1 = (((bb[2] + 16.0) * ppp) as u32).min(img.width());
+ let y1 = (((bb[3] + 46.0) * ppp) as u32).min(img.height());
+ image::imageops::crop_imm(&img, x0, y0, x1 - x0, y1 - y0).to_image()
+ }
+ None => img,
+ };
+ std::fs::create_dir_all(&dir).unwrap();
+ let path = dir.join(format!("{name}.png"));
+ img.save(&path).unwrap();
+ eprintln!("snapshot: {}", path.display());
+ }
+}
+
+fn label(d: &mut Driver, kind: &str, index: usize) -> Value {
+ d.exec("sequence.inspect", json!({}))[kind][index]["label"].clone()
+}
+
+#[test]
+fn the_track_header_strip_sets_a_colour_label() {
+ let mut d = Driver::demo();
+ assert_eq!(label(&mut d, "video", 0), json!(null));
+ let ids = d.ids("timeline.track.");
+ for id in ["timeline.track.V1.color", "timeline.track.A1.color"] {
+ assert!(ids.iter().any(|i| i == id), "{id} missing from {ids:?}");
+ }
+ // the strip sits left of the source patch, inside the header
+ let strip = d.element("timeline.track.V1.color").unwrap();
+ let patch = d.element("timeline.track.V1.sourcePatch").unwrap();
+ assert!(strip[0] + strip[2] <= patch[0], "strip {strip:?} overlaps the source patch {patch:?}");
+ d.click("timeline.track.V1.color");
+ let menu = d.ids("timeline.track.V1.color.");
+ assert!(menu.iter().any(|i| i == "timeline.track.V1.color.Forest") && menu.iter().any(|i| i == "timeline.track.V1.color.None"), "{menu:?}");
+ d.click("timeline.track.V1.color.Forest");
+ assert_eq!(label(&mut d, "video", 0), json!("Forest"));
+ assert!(!d.ids("timeline.track.V1.color.").iter().any(|i| i == "timeline.track.V1.color.Forest"), "the menu closes");
+ // audio tracks too
+ d.click("timeline.track.A1.color");
+ d.click("timeline.track.A1.color.Mango");
+ assert_eq!(label(&mut d, "audio", 0), json!("Mango"));
+ d.snapshot("track-color-labels", None);
+ // None clears; undo brings it back
+ d.click("timeline.track.V1.color");
+ d.click("timeline.track.V1.color.None");
+ assert_eq!(label(&mut d, "video", 0), json!(null));
+ d.exec("edit.undo", json!({}));
+ assert_eq!(label(&mut d, "video", 0), json!("Forest"));
+}
diff --git a/docs/gaps.md b/docs/gaps.md
index 259b9d042..428c3bddd 100644
--- a/docs/gaps.md
+++ b/docs/gaps.md
@@ -27,7 +27,7 @@ platforms** G4, G9, G17; **performance** G16; **ecosystem** G11; **measurement**
| G11 | No plugin hosting | ecosystem | no | 200–400 h |
| G12 | AI features | AI | no | 150–300 h |
| G13 | Delivery formats | file format | no | 60–110 h |
-| G14 | Localization: 8 of the 12 key languages missing | localization | no | 150–230 h |
+| G14 | Localization: 3 of the 12 key languages missing | localization | no | 150–230 h |
| G15 | Interchange never validated in Avid / Pro Tools; slow XML import | file format | partly | 20–40 h |
| G16 | Performance reports on 0.5.0 | performance | partly | 30–60 h |
| G17 | Audio device and playback reliability | stability | partly | 20–40 h |
@@ -231,22 +231,26 @@ platforms** G4, G9, G17; **performance** G16; **ecosystem** G11; **measurement**
(audio-only `.m4a`, or ADTS `.aac`; #814); ProRes 4444 / 4444 XQ in the export UI (#342).
- **Estimate:** 60–110 h. Doc: [file-format-parity.md](file-format-parity.md).
-## G14. Localization: 8 of the 12 key languages missing
+## G14. Localization: 3 of the 12 key languages missing (Hindi, Arabic, Vietnamese)
- **Have:** Spanish, Japanese, Simplified Chinese, French (#498) and Portuguese (Brazil) (#859)
catalogs cover ~99.6–100% of the ~3,500 cataloged strings; Ukrainian ~10% (menus).
- **Missing:** Hindi, Arabic (no RTL interface layout or catalog; the interface has Arabic and Hebrew
fallback fonts and shows captions in reading order, but other names and fields keep egui's
left-to-right run order; Arabic titles reported broken, #395),
- German beyond menus (#490), Korean (#508; needs Hangul fonts in craft-fonts),
+ Korean (#508; needs Hangul fonts in craft-fonts),
Vietnamese; Premiere also ships Russian. Engine errors,
- CLI and MCP stay English. No language has a recorded native-speaker review.
+ CLI and MCP stay English. Apart from the German menus (#630), no language has a recorded
+ native-speaker review.
- **Done:** Indonesian (#867): `id.tsv` has every entry of the Spanish catalog (~100%), in Edit ▸
Language, Settings ▸ General and the native macOS menu; System Language picks it for `id-*` (and
legacy `in-*`) locales. Native-speaker review welcome.
- **Done:** Italian: `it.tsv` has every entry of the Spanish catalog (~100%), in Edit ▸ Language,
Settings ▸ General and the native macOS menu; System Language picks it for `it-*` locales.
Native-speaker review welcome.
+- **Done:** German: `de.tsv` has every entry of the Spanish catalog (~100%), beyond the menus of
+ #630 (panels, dialogs, effects and their parameters, settings, status messages). The menus are
+ native-reviewed; review of the rest welcome.
- **Estimate:** 150–230 h. Doc: [localization-parity.md](localization-parity.md).
## G15. Interchange never validated in Avid / Pro Tools; slow XML import
diff --git a/docs/graphics.md b/docs/graphics.md
index cacf61732..61030d146 100644
--- a/docs/graphics.md
+++ b/docs/graphics.md
@@ -13,7 +13,10 @@ kerning and ligatures, bidi, line breaking, all drawn as vectors in linear light
- Its **layers** are effect instances `graphic_text` / `graphic_shape` in the clip's effect list,
in paint order (first = back). They are hidden from the Effects panel. Because they are effect
instances they save with the project, take keyframes on every animatable property (Source Text
- keyframes hold), appear in Effect Controls and copy with the clip. Standard effects on a graphic
+ keyframes hold), appear in Effect Controls and copy with the clip. The Essential Graphics
+ panel's number and point properties (Tracking, Leading, Font Size, Position, Opacity…) carry
+ the same stopwatch as Effect Controls (`graphics.prop..stopwatch`, #2358): once a property
+ animates, changing it in the panel adds or updates a keyframe at the playhead. Standard effects on a graphic
clip apply to the composed graphic; Motion and Opacity apply last.
- `filmcraft_project::graphic::eval_layer` evaluates a layer at a time into a `LayerSpec`.
- Projects with graphics need no schema migration: everything is additive (new item kind, new
diff --git a/docs/images/filmcraft-lumetri.png b/docs/images/filmcraft-color-panel.png
similarity index 100%
rename from docs/images/filmcraft-lumetri.png
rename to docs/images/filmcraft-color-panel.png
diff --git a/docs/images/filmcraft-lumetri.png.attribution b/docs/images/filmcraft-color-panel.png.attribution
similarity index 91%
rename from docs/images/filmcraft-lumetri.png.attribution
rename to docs/images/filmcraft-color-panel.png.attribution
index 4e6f6ceb4..2cbab37de 100644
--- a/docs/images/filmcraft-lumetri.png.attribution
+++ b/docs/images/filmcraft-color-panel.png.attribution
@@ -1,11 +1,11 @@
-asset: filmcraft-lumetri.png
-title: README: Lumetri Color panel
+asset: filmcraft-color-panel.png
+title: README: color grading panel
author: FilmCraft contributors (screenshot); film/footage/music credits below
source: original work (screenshot of FilmCraft captured with its ui.screenshot control command)
license: MIT OR Apache-2.0 (screenshot); embedded film frames are public domain, music CC0-1.0
license-file:
added: 2026-09-30 by Claude (agent) for Brandon Thomas
-notes: Crop of the Lumetri Color panel (Basic Correction, Color Wheels) while grading Charade (1963); shows panel controls only. All UI icons are drawn in code; fonts are Inter and JetBrains Mono (OFL-1.1). Contains no Adobe artwork.
+notes: Crop of the color grading panel (Basic Correction, Color Wheels) while grading Charade (1963); shows panel controls only. All UI icons are drawn in code; fonts are Inter and JetBrains Mono (OFL-1.1). Contains no Adobe artwork.
Media visible in the screenshot (none of it is committed to the repository):
- Night of the Living Dead (1968), dir. George A. Romero, Image Ten. US public domain (released without a copyright notice). Source: https://archive.org/details/night-of-the-living-dead-1968-english (Public Domain Mark).
- Carnival of Souls (1962), dir. Herk Harvey, Harcourt Productions. US public domain. Source: https://archive.org/details/CarnivalOfSoulsVideoQualityUpgrade (Public Domain Mark).
diff --git a/docs/localization-parity.md b/docs/localization-parity.md
index 211ab579e..ed8520ee6 100644
--- a/docs/localization-parity.md
+++ b/docs/localization-parity.md
@@ -1,6 +1,6 @@
# Localization parity
-> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (Korean covers the whole interface, #508; Czech interface catalog) · **Target:** Adobe Premiere Pro 2026 (26.5.2)
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (German covers the whole interface; Czech interface catalog) · **Target:** Adobe Premiere Pro 2026 (26.5.2)
Per-language status of FilmCraft's interface. Premiere 26.5.2 ships 10 interface languages (the
installed bundle's `.lproj` folders): German, English, Spanish, French, Italian, Japanese, Korean,
@@ -17,8 +17,8 @@ are reachable over the control channel. One catalog per language,
commands, panels, workspaces, presets) are translated where they are drawn. Searches match the
displayed labels as well as English sources. Tests fail when a `tl!` literal, a menu label or a
registry name has no Spanish entry; `zh-cn.tsv` must also cover every `tl!` literal and menu
-label; `ja.tsv`, `fr.tsv` and `pt-br.tsv` have the same entries but are not yet required by tests
-(French must cover the core menus, Brazilian Portuguese every menu label, and neither may keep an
+label; `ja.tsv`, `fr.tsv`, `pt-br.tsv` and `de.tsv` have the same entries but are not yet required by tests
+(French and German must cover the core menus, Brazilian Portuguese every menu label, and neither may keep an
entry without a Spanish one). Engine error messages, the
control channel, the CLI and MCP stay English.
@@ -50,18 +50,23 @@ whole interface, one PR) at ~4–8 h per language for the catalog plus tests.
| Portuguese (Brazil) | pt-br | 3,541 (same entries as Spanish, plus the macOS Settings item) | as Spanish | Latin (bundled fonts) | not recorded; welcome | partial (#859) | review |
| Indonesian | id | 3,541 (same entries as Spanish, plus the macOS Settings item); must cover the core menus, no entry without a Spanish one | as Spanish | Latin (bundled fonts); System Language also maps the legacy `in` code | not recorded; welcome | partial (#867) | review |
| Japanese | ja | 3,487 (99.7%) | as zh-cn; system-font kanji may pick the Chinese fallback (#547) | CJK fonts, vertical title text | not recorded | partial | 4–8 h + review |
-| German | de | 371 (10.6%) | menus only | Latin | yes (#630) | menus only | 5–9 h + review |
+| German | de | 3,590 (same entries as Spanish); must cover the core menus and the macOS app menu, no entry without a Spanish one | as Spanish | Latin (bundled fonts) | menus yes (#630); the rest not recorded, welcome | partial | review |
| Korean | ko | 3,573 (same entries as Spanish, plus the macOS Settings item) | as Spanish | installed system Hangul font (Malgun Gothic, Apple SD Gothic Neo, Noto Sans CJK KR…); refused without one | not recorded; welcome | partial (#508) | review; Hangul in craft-fonts for the web |
| Vietnamese | vi | 0 (0%) | — | Latin with stacked diacritics (font coverage to check) | — | none | 6–12 h + review |
| *Other shipped:* Italian | it | 3,573 (same entries as Spanish, plus the macOS Settings item); must cover the core menus, no entry without a Spanish one | as Spanish | Latin (bundled fonts) | not recorded; welcome | partial | review |
| Czech | cs | 3,591 (all Spanish source keys, plus the playback-resolution label `1/2`) | dialogs, Settings, effects, shortcuts, status; engine errors English | Latin (bundled fonts) | not reviewed | partial | native review |
| *Other shipped:* Ukrainian | uk | 351 (10.0%) | menus only | Cyrillic (bundled) | not recorded | menus only | 5–9 h |
+UI strings are catalog entries (the non-comment lines of `src/i18n/.tsv`; English counts the
+source strings in the code), so the rows were measured at different times: at this change the
+Spanish and German catalogs both have 3,590 entries, German every Spanish one. Strings added
+later may stay English in German until translated; only the core menus are required.
+
Premiere also ships Italian, which we now cover like Spanish, and Russian (6–10 h).
-**Localization dimension:** 6 of the 12 key languages near-complete (English, Spanish, Japanese,
-Simplified Chinese, French, Portuguese (Brazil)), 1 menus-only, 5 none; against Premiere's 10 languages
-we cover 6 well and 1 partly. **~35%, 150–230 h** for all twelve to `full` plus Italian and Russian, of which the script
+**Localization dimension:** 9 of the 12 key languages near-complete (English, Spanish, Japanese,
+Simplified Chinese, French, Portuguese (Brazil), Indonesian, Korean, German), 3 none (Hindi, Arabic,
+Vietnamese); against Premiere's 10 languages we cover 9 well and Russian partly. **~35%, 150–230 h** for all twelve to `full` plus Italian and Russian, of which the script
work (RTL and complex shaping in the egui interface) is the largest and least parallel part.
Every language needs native-speaker review (human).
@@ -89,5 +94,6 @@ creative effect names, and the shared `Subtitle` key (caption format and graphic
| Date | Change | Summary |
|---|---|---|
| 2026-10-19 | minor | Added Czech (`cs`) interface catalog and locale detection; rewrote all catalog rows with a binding glossary; AI-assisted, not yet proofread by a native speaker |
+| 2026-10-13 | minor | German (de) covers the whole interface: every entry of the Spanish catalog (3,590); the tests require the core menus and the macOS app menu and reject entries without a Spanish one |
| 2026-10-11 | minor | German (de) ships the menus (#630): 371 of 3,498 strings (10.6%), native-reviewed; dimension now 2 menus-only, 5 none |
| 2026-10-10 | major | Created from ROADMAP.md's "Interface localization" section; catalog coverage measured (es 3,496, ja 3,487, zh-cn 3,485, pt-br 348, uk 351 of 3,498); the 12-language table and script-support gaps added |