Files
amethyst/tools/material-symbols-subset
Claude a87222c51f refactor: split Compose UI out of commons into a new commonsUI module
`:commons` is on the CLI classpath, yet it declared Compose UI, Coil, Compose
resources, markdown and desktop Compose as dependencies, dragging ~40 MB of
UI/Skiko jars into every `amy` distribution. This moves every
Compose-dependent file into a new KMP module, `:commonsUI`, that
`api`-depends on `:commons`; `:commons` keeps only the Compose runtime
(stability annotations + snapshot state) and lifecycle-viewmodel.

Files keep their `com.vitorpamplona.amethyst.commons.*` packages, so the split
is a build-graph boundary and no consumer import changed. 236 files were
`git mv`'d (composables, icons, robohash, theme, Coil fetchers, the
`@Composable` relay-client entry points, `composeResources`, and the tests
that exercise them). Two headless files needed surgery instead of a move:
`GalleryParser` lost a vestigial foundation `@OptIn`, and the
`LocalPrivacyLockState`/`lockStateFor` CompositionLocal accessor moved out of
`PrivacyLockState` into its own commonsUI file. The feed DAL under `ui/feeds`
and `ui/note/ParentNote`+`ReplyContext` stay in `commons` because ViewModels
depend on them.

`amethyst`, `desktopApp`, `nappletHost` (NappletWebContract serves the shell
from composeResources) and `benchmark` now depend on `:commonsUI`; `cli`,
`geode` and `marmotBench` do not. commons' androidMain gains an explicit
androidx.core KTX dep it previously got transitively through Compose UI.

CI, crowdin, the icon-font tools and the escaping hook point at the new
composeResources location; CLAUDE.md, commons/ARCHITECTURE.md, a new
commonsUI/ARCHITECTURE.md, CONTRIBUTING, BUILDING and the affected skills
document the boundary. A plan doc under commons/plans records the
classification method and follow-ups.

Verified: JVM compiles for commons, commonsUI, cli, desktopApp; Android debug
compiles for nappletHost and amethyst; commons/commonsUI/cli JVM test suites;
both verifyKmpPurity gates; the cli runtime classpath no longer resolves
Compose UI, material3, Skiko or Coil.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N56KzPSYiN5edMRamvKEgD
2026-09-12 16:26:59 +00:00
..

Material Symbols Subset

The font shipped at commonsUI/src/commonMain/composeResources/font/material_symbols_outlined.ttf is a subset of Google's Material Symbols Outlined variable font, trimmed to only the codepoints referenced from commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt.

Full upstream Subset
Size ~11 MB ~410 KB
Glyphs ~3500 ~210

The subset cuts >10 MB out of every commons build artifact, every Android APK, and every Desktop app bundle.

When to regenerate

Run subset.sh whenever you:

  • add or remove a MaterialSymbol("\uXXXX") entry in MaterialSymbols.kt
  • pin a newer upstream font version

Prerequisites

pip install fonttools brotli

Regenerating

From the repo root:

./tools/material-symbols-subset/subset.sh

That downloads the upstream variable font, intersects its codepoints with the ones referenced from MaterialSymbols.kt, and overwrites the checked-in material_symbols_outlined.ttf.

If you already have an upstream .ttf on disk:

./tools/material-symbols-subset/subset.sh /path/to/MaterialSymbolsOutlined-Regular.ttf

Commit the regenerated .ttf alongside the MaterialSymbols.kt change.

How it works

pyftsubset (from fonttools) reads the codepoints we care about, drops every glyph and OpenType feature not reachable from those codepoints, and rewrites name, cmap, and GSUB tables accordingly. The Compose resource pipeline treats the result as a normal TTF — no code changes needed.

Custom glyphs

custom/ holds traced SVG outlines for icons the upstream font will never carry (third-party logos — currently the OpenTimestamps stamp). add_custom_glyphs.py bakes them into the subset TTF at end-of-PUA codepoints (U+F8F0 and up); subset.sh runs it automatically after pyftsubset, so regenerating the subset keeps them. To add one: trace the logo to a single-color SVG (potrace output works as-is), drop it in custom/, register it in the CUSTOM map in add_custom_glyphs.py, add the matching MaterialSymbol("\uF8Fx") to MaterialSymbols.kt, and rerun subset.sh (or add_custom_glyphs.py <ttf> to patch the existing font).