Commit Graph

25 Commits

Author SHA1 Message Date
bflatastic 98a6a3a041 UI: Arabic, Hebrew, Indic and Thai names can be typed and are drawn (#394)
Cause: two things kept Arabic out of a layer name on Windows.
- Windows switches the keyboard layout with Alt+Shift. Releasing Shift
  before Alt left Alt held alone, and the in-window menu bar (#279)
  counted the release as an Alt tap: it took the keyboard focus, the
  rename field closed, and the letters typed next were swallowed by the
  menu bar. The Project panel's rename field lost them the same way.
- The UI fonts are Inter plus the CJK system fallbacks, so Arabic,
  Hebrew, Indic and Thai names that did arrive (pasted, or from a
  project) showed as missing-glyph boxes.

Fix:
- An Alt tap only counts when Alt went down with no other modifier
  held, so Alt+Shift in either release order is no tap; a plain Alt tap
  still focuses the menu bar.
- The UI registers installed system faces for Arabic, Hebrew, Devanagari,
  Bengali, Gurmukhi, Gujarati, Tamil, Telugu, Kannada, Malayalam and Thai
  after the CJK ones, the same way (native only; the web build has no
  system fonts). A face covering several scripts is registered once
  (Segoe UI: Arabic and Hebrew; Nirmala UI: every Indic script).
- The text engine's fallback tries each script's plain platform families
  (Segoe UI, Nirmala UI, Leelawadee UI, Geeza Pro, Kohinoor, Noto…)
  before any covering face, so neither the UI nor a text layer gets a
  calligraphic face that merely sorts first.
- The Timeline's rename field registers `timeline.layer.<id>.nameEdit`.

egui 0.36 shapes each run of one face, so Arabic letters join and a word
reads right to left; it has no bidirectional layout, so the words of a
multi-word Arabic name (and mixed Arabic/Latin) still follow each other
left to right.

Tests: ui_inline_edit a_layout_switch_keeps_the_name_field_and_arabic_
names_are_kept (Alt+Shift both ways in the layer rename, Arabic typed and
stored; Hebrew/Devanagari/Thai in the Project panel; a plain Alt tap
still focuses File; failed before: the field closed), theme
installed_script_fallbacks_draw_arabic_hebrew_indic_and_thai_names
(failed before: replacement glyph for Arabic) and
arabic_words_are_joined_and_read_right_to_left, text
other_scripts_fall_back_to_a_plain_system_family and the script
classification.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:53:21 +07:00
Brandon Thomas a0c6a6e96e Merge pull request #401 from dmatviichuk/i18n/ukrainian
i18n: add Ukrainian (uk) menu translation

# Conflicts:
#	crates/text/src/fonts.rs
#	docs/preferences.md
2026-10-09 10:22:14 -04:00
Dmytro Matviichuk ceda5bd607
i18n: add Ukrainian menu translation (#395) 2026-10-09 14:46:20 +02:00
FeiLiuEM ad3da3c8de text, ui: follow a language change, and resolve the language before the fonts
Review follow-ups on #312:

- `crates/ui-egui/src/theme.rs`'s `japanese_font_tests` still called `install` with two
  arguments, so `cargo test` did not compile. Every call site now passes a language.
- The call sites passed the stored `general.language` preference. With the default `system`
  that is `""`, which handed the CJK choice back to the environment locale — one macOS and
  Windows usually do not set. They now pass `crate::i18n::language(app)`, the resolved
  language, so Match System draws Chinese on a Chinese system.
- Changing Settings ▸ General ▸ Language only reached the fonts on the first frame.
  `EffectcraftApp` now remembers the language its fonts were installed for and installs them
  again when it changes, so the switch applies without a restart.
- Documented that `fonts::set_cjk_locale` is process-global: the Han preference therefore
  applies to composition text as well as the interface chrome (docs/preferences.md and the
  function's own comment).

Rebased onto main after #309 landed — `header.rs` gained an `install` call site in the
meantime, and the catalogs now resolve through `i18n::language`.
2026-10-09 19:28:42 +08:00
FeiLiuEM a4d1e8d0b3 text, ui: the CJK fallback fonts follow the interface language
- `effectcraft_text::fonts::set_cjk_locale` lets the host say whose face should draw Han
  ideographs instead of leaving it to the locale environment, and drops the fallback cache when
  it changes. `han_order` reads that request first; the tag → order rule moves into the pure
  `han_order_for`, so it can be tested without touching process state.
- `theme::install` now takes the stored `general.language` value and registers one CJK system
  fallback per script in every font family, the interface's own script first: kana for Japanese,
  a Han character for `zh-hans` / `zh-hant`, then the other script so names in it still render.
  A face is registered at most once, and a machine with no CJK font installs nothing (the web
  build installs nothing, as before).
- Before this the probe was always `あ`, so Han text was drawn by the Japanese face whenever the
  operating system's locale was not Chinese: a Chinese interface, and Chinese file, layer or
  template names on any locale, both got Japanese glyph forms.
- Tests: the tag → order rule (`zh`, `zh_Hans`, `zh-Hant-TW`, `ko`, `ja`, `en`, empty), and the
  registration order plus once-only registration for a Chinese, a Japanese and an English
  interface.
2026-10-09 19:27:47 +08:00
Brandon Thomas 1f5218378c Merge pull request #298 from midasdf/fix/vertical-japanese-punctuation
M9: place Japanese vertical punctuation using font metrics
2026-10-09 00:04:52 -04:00
DWAA1660 8cb120d0ec Text: fallback skips a font whose glyph for the character is empty (#285)
Face::has_char counted any non-zero cmap entry as coverage. Some fonts map
whole scripts to empty glyphs (a decorative Latin font installed on a Linux
machine maps あ, 水, ア and 。 to glyphs with no contours), so once such a
face was loaded, fallback_for could pick it and Japanese text rendered as
nothing; cjk_falls_back_to_a_system_family failed whenever another test had
loaded that face first.

has_char (and file_covers, used for faces not yet loaded) now also require
the glyph to draw something: an outline with at least one segment, a colour
glyph, or a bitmap in any strike. Characters that are blank by nature
(whitespace, and the default-ignorable code points such as soft hyphen,
joiners and variation selectors) still count as covered by any mapping.
Face::glyph is unchanged, so shaping with the chosen face is as before.

Test: an_empty_glyph_does_not_cover_its_character builds a minimal TrueType
font in code (no font file added to the repo) mapping U+E000 to an empty
glyph and U+E001 to a triangle, and checks has_char and fallback_for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3vVft4VXvvy8SpbbUceTW
2026-10-08 16:48:13 +00:00
midasdf f224678541 M9: place Japanese vertical punctuation using font metrics
Co-Authored-By: Codex <noreply@openai.com>
2026-10-08 23:36:26 +09:00
Dexter 2e02523fe9 test: tolerate installed variants of bundled font families 2026-10-06 16:40:12 -05:00
BFlat c750b299cf
Merge pull request #118 from storytold/claude/system-fonts-rmnw4m
G2: font menus list the installed fonts
2026-10-07 00:37:13 +07:00
Claude dda9961889
G2: font menus list the installed fonts
A Windows user reported that the Properties panel's font menu offered only the bundled Inter,
JetBrains Mono and Noto Serif. The system font folders were scanned only when a project asked for
a family the bundled fonts lack, so until then every font menu (Properties, Character, Essential
Graphics) and `file.findMissing {what: fonts}` saw the bundled families alone, on every
platform. Listing the families now scans the system fonts first, and the desktop app starts that
scan on a background thread at launch so the menus are complete when first opened.

The style menus in the Properties and Character panels list the chosen family's own styles
instead of a fixed Regular / Medium / SemiBold / Bold / Italic. Both menus build their lists only
while open.

New query for agents: `text.fonts {query?, rescan?}` (MCP tool `list_fonts`) lists every family
with its styles, origin (bundled / system / user) and own-language name; `rescan` picks up fonts
installed since launch.

Tests: a fresh-process test that the family list includes every family in the platform's font
folders without a prior scan (failed before), and `text.fonts` filtering, rescan and per-family
styles, and the `list_fonts` MCP tool.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019EjTYdt76hTG4Kh2CJFnCr
2026-10-06 15:14:55 +00:00
Dexter 39e6907b5f G2: improve editing reliability and Windows rendering fidelity 2026-10-06 00:00:31 -05:00
fortesnow c8e9efb962 text: script-aware system font fallback and PostScript / full font names
Japanese (and Chinese, Korean) text in a family that lacks the glyphs, such as the default Inter,
rendered as missing-glyph boxes: `fallback_for` only searched the bundled faces and faces some
other layer had already loaded, so the result depended on render order. Now, after those cheap
candidates, it tries the platform's usual family for the character's writing system (kana and
hangul pick their language; Han ideographs follow the locale, Japanese first when it is unknown,
`EFFECTCRAFT_CJK_LOCALE` overrides) in the preferred face's style, and finally any installed face
that covers the character, reading files without keeping them. Results are cached per 256-character
block and preferred face.

`resolve` also accepts a face's full name (`Yu Gothic Bold`) or PostScript name (`YuGothic-Bold`),
which is how After Effects scripts set `textDocument.font`; the sfnt reader now records name id 6.

Tests: script classification, PostScript / full-name resolution on the bundled Inter, and (native,
skipped when no Japanese family is installed) that kana, ideographs and CJK punctuation in Inter
Bold fall back to an installed Japanese family's bold cut, with the cache returning the same face.
2026-10-06 10:41:15 +09:00
Brandon Thomas 0873393e43 Never crash: text layout and font resolution without expect()
Text layout and font resolution without expect(): an empty line list keeps the default bounds,
the line breaker stops instead of expect()ing a checked option, and font resolution falls back
to the first bundled face. The one remaining expect (the bundled-font database is never empty)
carries the documented narrow allow. Denies the panic lints in the crate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 13:27:38 -04:00
Brandon Thomas c3532df7ef M13.12: Variable Font Axes animators change advances (text re-spaced)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:34:15 -04:00
Brandon Thomas f89af341a6 M13.6: variable font axes in the character style
CharStyle/TextDoc variations (layer.setText variations), shaped with harfrust instances so
advances follow HVAR/gvar, outlines drawn at the design-space position, animator deltas relative
to the style's values, Character panel Variable Font Axes fields (character.axis.<tag>).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:36:53 -04:00
Brandon Thomas 7ac5317ce9 Merge main into M13.2 2026-10-03 04:19:01 -04:00
Brandon Thomas 30a92ba82f M13.2: OpenType features (stylistic sets, figures, fractions, ordinals, dlig, true small caps / superscripts with faux fallback), Character panel OpenType popup, text.fontFeatures
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:53:05 -04:00
Brandon Thomas b17d2c05e6 Merge main into M14.5 (settings and menus)
Reconciled with main's keyframe labels (same Keyframe::label field; keys.setLabel and
keys.selectLabelGroup from main are kept, M14.5's duplicates removed; Edit ▸ Label on
selected keys delegates to the label helper), proxies (RenderOpts::proxy next to
nested_switches/draft_shadows), offloaded renders (Work carries nested_switches), wasm
audio pump (preview mix rate), variable font axes and mask feather points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:11:45 -04:00
Brandon Thomas f855a4b55b M14.5: wire the remaining settings; keyframe assistants and labels; AE menu entries
Settings: 56 of 59 not-yet-wired settings now change behaviour (nested-comp switches,
constant vertex count, related-item time sync, match-name pick whip, split-layer order,
Home on open, motion path span, internal wireframes, zoom quality, label-coloured tabs,
mask colour cycling, gradients, grid/guide styles, text engine, font preview/recent/native
names, missing frames, unlabeled alpha, drag import, default output folder, segmenting,
bit depth names, preview sample rate, disk/media/conformed-audio caches, RAM reserve and
low-memory reduction, Video Preview window, 3D reference axes/extended viewer/draft
shadows, script file gate + File.execute warning, expression editor options and error
banner). Three stay display-only and are documented.

Features: Convert Audio to Keyframes, RPF Camera Import (JSON/CSV camera data),
keyframe colour labels + Select Keyframe Label Group, Recent Animation Presets.
Menus: Edit > History, File > Import Recent Footage, Replace Footage > With Layered
Comp, Save a Copy As XML (.ecprojx, opens again), Composition > VR (Create VR
Environment, Extract Cubemap), Assign Shortcut to 3D view / workspace, Window viewer
labels + open viewers, Help > System Compatibility Report / Enable Logging / Reveal
Logging File. Dynamic menu nodes (@dynamic:…) shared by the egui and native menus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:45:44 -04:00
Brandon Thomas 7537eea85c M13.5: Animate Text > Variable Font Axes
Text: text.animatorFontAxes (replaces the stub) lists the layer font's
variation axes (skrifa) or adds an animator property that offsets one axis
(weighted by the selectors, from the axis default); the renderer redraws each
character's outline at its design-space position (cached per location). The
Timeline's Animate: menu lists the font's axes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 00:24:05 -04:00
Brandon Thomas 1ebfef77c4 M13.5: vertical Roman, tate-chu-yoko, forced LTR, animated caret, Lottie style runs
Text: vertical type turns Roman characters on their side (CJK stays
upright) unless Standard Vertical Roman Alignment is on; Tate-Chu-Yoko sets
selected characters horizontally in a one-em cell of the column (layer.setText
tateChuYoko / verticalRomanUpright, Character panel toggles). A Left-to-Right
paragraph is now forced LTR instead of auto-detected. The editing caret follows
animators and text on a path (render::text::caret_maps). Lottie export writes
per-character style runs as index-unit range animators.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 00:01:24 -04:00
Brandon Thomas f78435927b M9.9: text style runs + paragraph settings
TextDoc gains character style runs (font, size, colours, tracking, leading,
baseline shift, h/v scale, tsume, faux styles, caps, super/subscript, kerning
metrics/optical/manual, ligatures) and per-paragraph settings (justification
with last-line modes, indents, space before/after, direction, composer,
hanging punctuation), serde-compatible with single-style documents. Layout
handles mixed runs on a line (shared baseline, largest leading), every-line
composer, editing geometry (carets, hit testing, selection quads) and basic
vertical type. Renderer colours per run. Expressions get the sourceText style
API (style, getStyleAt, createStyle, setters with character ranges).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:34:13 -04:00
Brandon Thomas c5cf189e1a M9.6: text animation depth (selectors, animator properties, per-char 3D, path text, presets)
Range selector complete (units, based on, modes, shapes, smoothness, ease
high/low, randomize), Wiggly and Expression selectors combined by mode;
all AE animator properties incl. line anchor, character offset/value,
skew axis, tracking type, fill/stroke HSB+opacity, blur; More Options
(anchor grouping, fill & stroke order, inter-character blending); Path
Options (text on a mask path); per-character 3D rendered as planes in
the 3D compositor; text animation commands and original presets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 00:01:19 -04:00
Brandon Thomas 808cd490cd M0.1–M0.7: workspace, time/geom/color/keyframe/project/raster/path/text/effects/render crates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:05:20 -04:00