read_face (crates/text/src/sfnt.rs) also listed faces with none of the
tables skrifa reads glyph outlines from (glyf, CFF, CFF2, VARC), such
as faces whose glyphs are bitmaps only or whose outlines are in Apple's
hvgl table. The renderer draws glyphs only from those outlines, so text
set in such a face is blank. On macOS 27.0.1 the system scan listed
"GB18030 Bitmap" (NISC18030.ttf, bdat bitmaps), so it appeared in the
Font menus.
read_face now returns no face when the table directory has none of
these tables, before it reads the name table. In a collection, the
faces with outlines keep their index. VectorCraft's font scan has the
same check (storytold/vectorcraft#781).
The vertical layout path never emitted underline rectangles, so layer and
run underlines were a no-op. Place a tall strip to the right of each
underlined cell (vertical-rl) and compare horizontal vs vertical "A" at 60px.
Plain layout() underlines sat on the unshifted baseline while layout_rich()
runs already subtracted baseline_shift. Match the two so underline y tracks
the glyphs for a full-paragraph style.
A text layer is now one of two types, each with Premiere Pro 26's handles:
- Point text (Type tool click): every handle scales the layer about its
anchor point, both axes alike; the font size is untouched.
- Paragraph text (Type tool drag): the dragged rectangle is a box the text
wraps in. Handles move that side or corner of the box, the opposite side
stays, the text re-wraps at the same size. Lines below the box are not
shown and the bottom-right handle turns into a red plus.
- The anchor point can be dragged with the Selection tool; the layer stays.
It is picked before anything under it, so a shape dragged by its exact
centre moves its anchor.
- Properties > Text > wrench opens Text Properties, where Text Layer Type
switches a layer between the two (graphics.setTextType); the text stays
where it is.
Shapes keep stretching away from their opposite side.
New: text layer parameter box_height, graphics.newText `box`, and
textType / box / overflow / anchor / scale in graphics.list. A layer saved
before a parameter existed can now be given it with graphics.set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The merged Japanese interface (#38) looked only for a system font. When
FilmCraft is built with craft-fonts, theme::install already appends the
Japanese faces to every font family, so switching to Japanese uses them
(no system scan) and works on the web too; otherwise it falls back to an
installed system font as before. Docs use an absolute CRAFT_FONTS_DIR
(build.rs runs in crates/text, so a relative path resolves from there).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
crates/text/build.rs embeds the fonts of a storytold/craft-fonts checkout
named by CRAFT_FONTS_DIR as filmcraft_text::fonts::CRAFT_FONTS (native:
all of them; wasm32: only BIZ UDPGothic Regular). Unset, CRAFT_FONTS is
empty and nothing changes. A bad CRAFT_FONTS_DIR is a warning, or an
error with CRAFT_FONTS_REQUIRED=1. Never a Cargo dependency, no network.
- UI: the Japanese faces are the last fallback of every egui font family
(BIZ UDPGothic first, Bold first in the semibold/medium families).
- Text engine: registered after the bundled faces; fallback_for picks
them after the bundled faces and before system faces (Mincho for serif
text, Gothic otherwise, nearest weight).
- Tests: Japanese glyphs (no tofu) in the UI and title paths, skipped
without craft-fonts; the theme works with CRAFT_FONTS empty.
- Release: every build job checks out craft-fonts at a pinned commit and
builds with CRAFT_FONTS_DIR + CRAFT_FONTS_REQUIRED; packages carry
OFL-<family>.txt. NOTICE, ATTRIBUTION.md (optional build input), AGENTS.md,
CLAUDE.md, README and docs/contributing.md describe it.
FilmCraft main bundles no Japanese font, so no font files move.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Edit > Language switches English/Japanese and persists in UI state
(`app.language.english` / `app.language.japanese`, reachable through the
control channel). Core native and in-window menu labels are translated;
untranslated labels stay English. The in-window header fits the document
title beside the localized menus.
No font is bundled. Japanese text uses a Japanese font already installed on
the system (Hiragino, Yu Gothic, Meiryo, Noto Sans CJK JP, Source Han Sans,
IPA, … or any installed face covering the menus' characters), added to every
theme font family as the last fallback. Without one, switching to Japanese is
refused with a message and a saved Japanese setting falls back to English
(the web build cannot read system fonts). Titles already fall back to
installed fonts through the text engine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rust/clippy 1.99 added `chunks_exact_to_as_chunks` and tightened
`needless_late_init` and `drain_collect`, failing `clippy -D warnings`
on main.
- `chunks_exact(N)` / `chunks_exact_mut(N)` with a constant N become
`as_chunks::<N>()` / `as_chunks_mut::<N>()` (fixed-size arrays, so
several byte reads drop their per-element indexing). relink's
fingerprint uses the `(chunks, remainder)` split; its hash output is
unchanged.
- Late-initialised `let`s in ac3 bit allocation and opus CELT
bands/rate become `let x = if/match …`.
- `dpb.drain(..).collect()` becomes `std::mem::take(&mut dpb)`.
No behaviour change; `cargo xtask ci` passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- interchange: exporters (FCP7 XML, FCPXML, OTIO) skip a missing nested sequence or media with a
report warning instead of `expect`/`unwrap`; EDL event grouping and M2 lines, the XML writer
and the AAF/OMF dispatch arms have no panics. The WAVE header saturates instead of overflowing
for >4 GiB descriptors (found by fuzzing: a mutated EDL exported to OMF), regression test
`wav::tests::huge_wav_header_saturates`.
- captions: EBU STL frame rate read with `get()`; MCC rows, TTML text and the STL dispatch arm
without `expect`/`unreachable!`.
- project: bin moves, 5.1 pan lanes and text/shape layer constructors without `expect`.
- text: font resolution and line layout without `expect` (the bundled-face lookup keeps one
documented `#[allow(clippy::expect_used)]`: the faces are compiled in).
- automation: the MCP bridge returns an error instead of `expect` when not connected.
- Each crate denies unwrap/expect/panic/unimplemented/todo/unreachable outside tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vertical text layout in the text engine (one line per character, columns right to left).
All edits are undoable engine commands; engine tests cover each menu group.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- New L1 crate filmcraft-text: fonts (bundled Inter Regular/Medium/SemiBold/Bold/Italic,
JetBrains Mono, Noto Serif; DirectorySource scans system font folders reading only name/OS2
tables; family/style resolution with synthetic bold/italic; per-char fallback), layout
(harfrust kerning/ligatures, unicode-bidi, unicode-linebreak, alignment incl. justify,
leading, tracking, baseline shift, all/small caps, underline, carets/hit-test/selection,
cached), raster (moved from captions; active-edge list, shapes, emboldening), render
(outline + sub-pixel glyph-mask caches; transformed-outline path for rotation/skew),
mask (distance-transform strokes, blur).
- Captions burn-in now shapes and kerns via the engine (font.rs/raster.rs removed).
- Timecode / Clip Name effects draw real text (full clip names, not seven-segment digits);
text_burnin golden re-blessed.
- UI takes its font bytes from the text crate (no duplicate copies in the binary).
- New fonts: Inter Bold, Inter Italic (OFL-1.1, rsms/inter v4.1), Noto Serif Regular
(OFL-1.1, notofonts) with sidecars, ATTRIBUTION.md rows and licence text.
- Perf: 3-line 96 px title at 1080p ~1.6 ms cold / 0.15 ms warm (release).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>