# Material Symbols & Material Icons — Admin & Architecture Guide

This guide is for engineers, architects, and operators who need to understand how `google/material-design-icons` is **built**, not just how to consume it. It documents the repository's true nature — a generated mirror of Google's upstream icon pipeline — the Python toolchain that regenerates it, the CI automation that runs weekly, the asset-versioning model, and the operational concerns of cloning, mirroring, or vendoring this distribution.

> [!IMPORTANT]
> This repository is **not a conventional software project**. It is an automated *asset distribution*: roughly five million generated icon files plus a small (~19 KB) Python toolchain that downloads and lays them out. There is no application to run, no server, no API of its own. The "internals" worth understanding are the generator scripts and the CI that invokes them.

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [System Architecture](#2-system-architecture)
3. [Repository Structure](#3-repository-structure)
4. [The Update Toolchain](#4-the-update-toolchain)
5. [Asset Versioning Model](#5-asset-versioning-model)
6. [CI / Automation](#6-ci--automation)
7. [Requirements](#7-requirements)
8. [Operations](#8-operations)
9. [Security Analysis](#9-security-analysis)
10. [Code Quality & Patterns](#10-code-quality--patterns)
11. [Potential Improvements](#11-potential-improvements)
12. [Quick Reference](#12-quick-reference)

---

## 1. Executive Summary

| Aspect | Detail |
|---|---|
| Purpose | Official distribution of Material Symbols (current) and Material Icons (classic) icon assets |
| Nature | Generated mirror — assets are downloaded from `fonts.google.com`, not authored here |
| Source of truth | Google Fonts upstream (`fonts.google.com/metadata/icons`) |
| Generator | `update/` Python toolchain (`update_repo.py`, `update_symbols.py`, `icons.py`) |
| Automation | GitHub Actions, weekly cron (Fridays 02:00 UTC), commits regenerated assets to `master` |
| Scale | ~4.8 million files; ~19 KB of actual source code |
| Sets | 2 (Symbols, Icons) × up to 5 styles × 18 categories × multiple sizes/densities/axes |
| License | Apache License 2.0 |
| Contribution model | No icon PRs accepted; assets are upstream-generated |

> [!NOTE]
> Because assets are generated, the meaningful "code" surface is three short Python files. Everything else is output. Treat the repo as a build *artifact store* with a build script attached, and most operational decisions follow naturally.

---

## 2. System Architecture

The repository sits at the **downstream** end of an internal Google pipeline. It does not design icons; it harvests already-published assets from the public Google Fonts endpoints and arranges them into a stable, browsable directory tree.

```text
            ┌─────────────────────────────────────────────┐
            │  Google Fonts upstream (internal pipeline)   │
            │  - icon designs, versions, family metadata   │
            └───────────────┬─────────────────────────────┘
                            │  public HTTP endpoints
                            │  fonts.google.com/metadata/icons
                            │  {host}/s/i/...   (per-asset URLs)
                            │  fonts.googleapis.com/css2  (fonts)
                            ▼
   ┌──────────────────────────────────────────────────────────┐
   │  update/ toolchain (this repo)                            │
   │                                                          │
   │  update_repo.py     → classic Material Icons assets       │
   │  update_symbols.py  → current Material Symbols assets      │
   │  icons.py           → font → codepoints extraction         │
   │  current_versions.json → per-icon version gate (skip set)  │
   └───────────────┬──────────────────────────────────────────┘
                   │  writes files into sibling dirs
                   ▼
   ┌──────────────────────────────────────────────────────────┐
   │  Asset tree (committed to git, served to users)           │
   │  src/ png/ android/ ios/ font/ symbols/ variablefont/     │
   └───────────────┬──────────────────────────────────────────┘
                   │  git commit + push (GitHub Actions)
                   ▼
            ┌────────────────────────────┐
            │  GitHub: google/material-   │
            │  design-icons @ master      │
            └────────────────────────────┘
                   │
                   ▼  consumed by
        users, fonts.google.com/icons browser,
        community npm packages, IDE asset tools
```

**Data flow, end to end:**

1. The toolchain fetches the icon **metadata** index from `fonts.google.com/metadata/icons` (a JSON document with a 5-character prefix stripped before parsing).
2. For each icon whose upstream `version` exceeds the version recorded in `current_versions.json`, it computes a set of **fetch URLs** from templated patterns and downloads each asset.
3. ZIP assets (Android/iOS/PNG bundles) are exploded in place; CSS responses from the Fonts API are followed to the real font binary and downloaded.
4. For each downloaded font, `icons.py` enumerates ligatures to emit a `.codepoints` sidecar mapping icon name → Unicode codepoint.
5. `current_versions.json` is rewritten with the new versions, and CI commits the changed assets.

> [!NOTE]
> The architecture has no persistent services and no state beyond `current_versions.json`. That single file is the entire incremental-update memory — it is what lets a weekly run download only what changed.

---

## 3. Repository Structure

```text
material-design-icons/
├── README.md                Set overview, usage pointers, update history
├── LICENSE                  Apache 2.0
├── .gitignore               Ignores venvs, node_modules, __pycache__
├── .github/
│   └── workflows/
│       └── main.yml         Weekly CI that runs update_symbols.py
├── update/                  ← the only real "code"
│   ├── update_repo.py       Classic Material Icons generator
│   ├── update_symbols.py    Current Material Symbols generator
│   ├── icons.py             Font → (name, codepoint) extractor
│   ├── requirements.txt     Python deps for the toolchain
│   └── current_versions.json  Per-icon version ledger (large, generated)
│
│   ── Generated asset trees (classic Material Icons) ──
├── src/                     Source SVGs, 24px, 5 styles
├── png/                     Raster PNGs, 18–48dp × 1x/2x/3x
├── android/                 Android vector drawables + density PNGs
├── ios/                     Xcode .xcassets imagesets (1x/2x/3x)
├── font/                    Static fonts (.otf/.ttf) + .codepoints
│
│   ── Generated asset trees (current Material Symbols) ──
├── symbols/
│   ├── web/                 SVG per axis variant
│   ├── android/             Vector XML per axis variant
│   └── ios/                 SVG (fill/grade variants; no weight)
└── variablefont/            Variable fonts (.ttf/.woff2) + .codepoints
```

| Path | Tracked code? | Role |
|---|---|---|
| `update/*.py` | Yes (source) | Generators + font extractor |
| `update/requirements.txt` | Yes (source) | Dependency pins |
| `update/current_versions.json` | Yes (generated) | Incremental-update ledger |
| `.github/workflows/main.yml` | Yes (source) | Weekly regeneration CI |
| `src/ png/ android/ ios/ font/ symbols/ variablefont/` | No (generated) | The published assets |

> [!IMPORTANT]
> Only `update/` and `.github/` contain human-authored content. The seven asset directories are machine output. Code review, security scanning, and "what changed" analysis should focus almost entirely on `update/` and the workflow file.

---

## 4. The Update Toolchain

Both generators share the same shape: define a set of `(source URL pattern, destination path pattern)` **Asset** tuples, expand them across every icon × style × size × axis combination, fetch, and post-process. They are built on Google's `absl` library for flags and app entry.

### 4.1 `update_repo.py` — classic Material Icons

Downloads the classic set. Drives off `fonts.google.com/metadata/icons?incomplete=1`.

**Per-icon assets** (`_ICON_ASSETS`) — for each icon, style, and size:

| Destination pattern | Asset |
|---|---|
| `src/{category}/{name}/{set}/{size}px.svg` | Source SVG |
| `android/{category}/{name}/{set}/black.zip` | Android bundle (exploded) |
| `ios/{category}/{name}/{set}/black.zip` | iOS bundle (exploded) |
| `png/{category}/{name}/{set}/{18,24,36,48}dp.zip` | PNG bundles (exploded) |

**Per-style assets** (`_SET_ASSETS`): a CSS request to `fonts.googleapis.com/css2?family={set}` whose response is parsed to find the real `.otf`/`.ttf` URL, which is then downloaded into `font/`.

**Command-line flags (absl):**

| Flag | Default | Effect |
|---|---|---|
| `--skip_existing` | `False` | Don't re-download assets that already exist locally (zips: skip if already exploded) |
| `--fetch` | `True` | Master switch; `--nofetch` dry-runs and reports what *would* be fetched |
| `--explode_zip_files` | `True` | Unzip downloaded `.zip` bundles and delete the archive |
| `--icon_limit N` | `0` | Process at most N icons (0 = all). Useful for testing |

```bash
# Dry run: list how many assets would change without downloading
cd update
python update_repo.py --nofetch
```

```text
123/2000 icons have changed
fetch disabled; not fetching 4567 assets
```

### 4.2 `update_symbols.py` — current Material Symbols

Downloads the current variable-font set. Drives off `fonts.google.com/metadata/icons?incomplete=1&key=material_symbols` and filters families to those containing `"Symbols"`.

The combinatorial expansion is the core of this script. For each symbol icon and style it iterates:

- **optical sizes:** `20, 24, 40, 48`
- **fill:** `""`, `fill1`
- **grade:** `gradN25`, `""`, `grad200`
- **weight:** `wght100..wght700` (web/android only; iOS gets no weight variants)

producing the axis-encoded filenames you see under `symbols/`.

| Destination pattern | Asset |
|---|---|
| `symbols/web/{name}/{set}/{name}{suffix}_{size}px.svg` | Web SVG |
| `symbols/android/{name}/{set}/{name}{suffix}_{size}px.xml` | Android vector XML |
| `symbols/ios/{name}/{set}/{name}{suffix}_symbol.svg` | iOS SVG (fill/grade only) |
| `variablefont/{set}[FILL,GRAD,opsz,wght].css` → `.woff2` → `.ttf` | Variable font |

Fonts are requested via the Fonts CSS API with the full axis range (`opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200`), downloaded as WOFF2, then **decompressed to TTF** with `fontTools.ttLib.woff2`.

**Command-line flags (absl):**

| Flag | Default | Effect |
|---|---|---|
| `--fetch` | `True` | Master fetch switch (`--nofetch` to dry-run) |
| `--overwrite` | `False` | Re-download and overwrite existing assets even if version unchanged |
| `--icon_limit N` | `0` | Process at most N icons |

> [!NOTE]
> `update_symbols.py` parallelizes downloads with `joblib.Parallel(n_jobs=50)` — fifty concurrent HTTP fetches — and sends a desktop-Chrome `User-Agent` header. Individual fetch failures are caught and printed rather than aborting the run, so a transient upstream error skips one asset rather than failing the whole job.

### 4.3 `icons.py` — font → codepoints extractor

A small utility that, given a built icon font, yields `(icon_name, codepoint)` pairs:

1. Loads the font with `fontTools.ttLib.TTFont`.
2. Builds a reverse cmap (glyph name → codepoint).
3. Walks the `GSUB` ligature lookups (type 4, plus type 7 extensions wrapping type 4) to reconstruct each icon's **ligature name** from its component glyphs.
4. Filters to codepoints in the Unicode **Private Use Areas** (where icon glyphs live) and emits the mapping.

This is what produces every `.codepoints` sidecar file in `font/` and `variablefont/`.

> [!TIP]
> `icons.py` is the most reusable piece of the toolchain — it is a general-purpose extractor for any Google-style ligature icon font, independent of this repo's directory conventions.

---

## 5. Asset Versioning Model

The repository has **no global semantic version**. Instead, every icon carries an independent integer version from upstream, recorded in `update/current_versions.json`.

```json
{
    "action::home": 18,
    "action::delete": 12,
    "symbols::home": 245
}
```

- Classic icons are keyed `"{category}::{name}"` (see `_version_key` in `update_repo.py`).
- Symbols are keyed `"symbols::{name}"` (see `_version_key` in `update_symbols.py`).
- On each run, an icon is **skipped** unless its upstream `version` is strictly greater than the recorded value (`--overwrite` bypasses this for symbols).
- After fetching, the file is rewritten sorted and indented, so diffs are readable.

> [!IMPORTANT]
> `current_versions.json` is the entire incremental-build cache. Deleting or corrupting it forces a **full re-download** of all assets on the next run. It is committed to git precisely so CI runs stay incremental.

The README also tracks a human-facing "update history" (e.g. 4.0.0 in 2020 restructured the repo; 3.0.0 in 2016 changed the license to Apache 2.0). These are coarse repository milestones, not per-icon versions.

---

## 6. CI / Automation

`.github/workflows/main.yml` regenerates the repository on a schedule.

```yaml
on:
  workflow_dispatch:        # manual trigger
  schedule:
  - cron: "0 2 * * 5"       # Fridays at 02:00 UTC
jobs:
  update-symbols:
    permissions:
      contents: write
    runs-on: ubuntu-latest
    steps:
    - name: free disk space        # reclaim space before a large checkout
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4 (python 3.11)
    - run: pip install -r update/requirements.txt
    - run: python update_symbols.py     # working-directory: ./update
    - name: commit                  # git add . ; commit if staged ; push origin master
```

Key operational facts:

- **Schedule:** weekly, Fridays 02:00 UTC. Also manually dispatchable.
- **Disk pre-clean:** the first step frees disk (swapoff, remove swapfile, `apt clean`, `docker image prune`) because the checked-out tree is multi-gigabyte and would otherwise exhaust the runner.
- **Scope:** the workflow runs **only `update_symbols.py`** — i.e. it refreshes the *current* Material Symbols set. The classic `update_repo.py` is **not** wired into CI, consistent with the classic set being frozen.
- **Commit policy:** `git diff --staged --quiet || git ... commit`. It commits only if there are staged changes, then pushes to `master` as the GitHub Actions bot.
- **Permissions:** `contents: write` so the bot can push.

> [!WARNING]
> The committed identity uses an empty email (`-c user.email='<>'`). This works for CI commits but means automated commits have no associated GitHub user. If you fork and enable the workflow, set a real bot identity to keep commit attribution clean.

> [!CAUTION]
> Because CI does `git add .` and pushes to `master`, anyone who forks and runs this workflow with `contents: write` will overwrite their fork's `master` with regenerated assets. Disable the schedule on forks you don't intend to keep current.

---

## 7. Requirements

### Toolchain runtime

| Requirement | Value |
|---|---|
| Python | 3.11 (per CI; `typed-ast` pin suggests 3.6–3.10 also work) |
| Network | Outbound HTTPS to `fonts.google.com` and `fonts.googleapis.com` |
| Disk | Several GB free (full asset tree) |
| OS | Any (CI uses `ubuntu-latest`) |

### Python dependencies (`update/requirements.txt`)

| Package | Pinned | Role |
|---|---|---|
| `absl-py` | 1.2.0 | CLI flags + app entry (`app.run(main)`) |
| `fonttools` | 4.14.0 | Font parsing, WOFF2 decompression, ligature walking |
| `requests` | 2.24.0 | HTTP downloads |
| `joblib` | 1.2.0 | Parallel fetch (`Parallel(n_jobs=50)`) in symbols generator |
| `brotli` | 1.0.9 | WOFF2 (brotli) decompression support |
| `regex` | 2020.7.14 | Pattern support |
| `click`, `black`, `pathspec`, `toml`, `typed-ast`, `attrs`, `appdirs`, `joblib`, `six`, `chardet`, `idna`, `urllib3`, `certifi` | various | Transitive / tooling |

> [!NOTE]
> The dependency pins are old (2020-era). They work for the toolchain's narrow needs but are not security-patched. See [§9](#9-security-analysis) and [§11](#11-potential-improvements).

> [!TIP]
> Install into a virtualenv — `.gitignore` already excludes `update/venv/` and `update/__pycache__/`:
> ```bash
> cd update
> python -m venv venv && source venv/bin/activate
> pip install -r requirements.txt
> ```

---

## 8. Operations

### 8.1 Cloning efficiently

A full clone is multi-gigabyte with millions of files. Choose the smallest checkout that meets your need.

```bash
# Shallow clone (latest snapshot, full tree)
git clone --depth 1 https://github.com/google/material-design-icons.git

# Sparse: only the current variable fonts
git clone --depth 1 --filter=blob:none --sparse \
  https://github.com/google/material-design-icons.git
cd material-design-icons
git sparse-checkout set variablefont symbols
```

> [!CAUTION]
> On Windows/NTFS, checking out the full tree is dominated by per-file creation cost for the millions of small assets and can take many minutes even after the pack downloads. Prefer sparse checkouts on Windows, or take only `font/` + `variablefont/` if you just need fonts.

### 8.2 Running a regeneration manually

```bash
cd update
source venv/bin/activate

# Classic Material Icons (small test first):
python update_repo.py --icon_limit 5

# Current Material Symbols (small test first):
python update_symbols.py --icon_limit 5
```

```text
5/5 icons have changed
Starting 1200 fetches
0/1200, estimating 90s left
...
```

> [!TIP]
> Always validate with `--icon_limit` (and `--nofetch` for a pure dry run) before a full run. A full symbols run fans out to tens of thousands of fetches at `n_jobs=50`.

### 8.3 Forcing a full refresh

```bash
# Symbols: ignore the version ledger and overwrite everything
python update_symbols.py --overwrite
```

To force the **classic** generator to redo everything, remove the relevant keys from (or reset) `current_versions.json` — `update_repo.py` has no `--overwrite`, it gates purely on the version ledger.

### 8.4 Mirroring / vendoring for production

For a production app you typically want a **pinned, minimal** subset, not a live mirror:

1. Take only the formats you ship (e.g. `variablefont/*.woff2` + `.codepoints`).
2. Self-host them; serve from your own origin to avoid third-party font CORS/availability dependence.
3. Pin to a specific commit so icon shapes don't shift under you (the repo is regenerated weekly).

> [!IMPORTANT]
> If you rely on the **hosted** Google Fonts font instead, you inherit Google's availability and any upstream icon renames/removals. For long-lived UIs, vendor a pinned snapshot.

### 8.5 Logs & observability

The scripts print progress to stdout only (no log files, no metrics). The classic generator prints periodic ETA lines every ~5 s; the symbols generator prints `"{i}/{total} complete"` every 5000 fetches. In CI, this stdout is the only run record — check the Actions run log for a regeneration's outcome.

---

## 9. Security Analysis

> [!NOTE]
> This is an asset repository with a tiny generator. The attack surface is small but worth stating precisely.

| Area | Assessment |
|---|---|
| Secrets | None in the repo. CI uses the default `GITHUB_TOKEN` via `contents: write`; no custom secrets are referenced. |
| Network trust | The generators fetch from `fonts.google.com` / `fonts.googleapis.com` over HTTPS and `write_bytes` the responses directly. They trust upstream content implicitly (no checksum/signature verification). |
| Input validation | Minimal. `update_symbols.py` asserts the parsed font URL ends in `.woff2`; `update_repo.py` asserts `.otf`/`.ttf`. The metadata JSON is consumed after stripping a 5-char prefix with no schema validation. |
| ZIP handling | `update_repo.py` calls `ZipFile.extractall()` on downloaded archives. `extractall` is vulnerable to path-traversal ("zip-slip") if an archive contains `../` entries. Acceptable only because the archives come from a trusted Google endpoint. |
| Code execution | None of user input; scripts are run by maintainers/CI, not exposed as a service. |
| Supply chain | Dependency pins are from 2020 and unpatched. `black==19.10b0` is a pre-release dev tool. None are run against untrusted input, limiting impact. |
| Auth / authz | N/A — no service. CI push is gated by GitHub repo permissions. |

**Hardening recommendations (for forks/mirrors):**

- Validate or sandbox `extractall` (e.g. reject entries with absolute paths or `..`) before trusting any upstream archive.
- Add response content-type/size sanity checks before `write_bytes`.
- Refresh dependency pins (see [§11](#11-potential-improvements)).
- Set a real CI bot identity rather than the empty email.

> [!CAUTION]
> If you point these scripts at any host other than Google's (e.g. a proxy/mirror), the implicit-trust model becomes a real risk: arbitrary downloaded bytes are written to disk and ZIPs are exploded without traversal checks. Only run against the trusted upstream.

---

## 10. Code Quality & Patterns

**Strengths:**

- **Declarative asset definitions.** Both generators express the entire output layout as a tuple of `Asset(src_pattern, dest_pattern)` records, expanded by `.format(**args)`. The directory conventions are fully described by these patterns — readable and self-documenting.
- **Incremental by design.** The version-ledger gate keeps weekly runs cheap.
- **Clean separation.** `icons.py` (font introspection) is decoupled from the fetch/layout logic.
- **Honest naming.** Both files' docstrings call themselves "Quick and dirty utility" — an accurate self-assessment.

**Weaknesses / debt:**

- **Duplication.** `update_repo.py` and `update_symbols.py` share large amounts of near-identical scaffolding (`Asset`/`Fetch`/`Icon` NamedTuples, `_pattern_args`, `_fetch_fonts`, `_create_fetch`, `current_versions` handling) with small divergences. A shared module would reduce drift.
- **Deeply nested combinatorial loop.** The symbols `main()` nests size → fill → grade → weight loops inline; the axis lists are hard-coded magic values.
- **Silent failure in symbols fetch.** `_do_fetch` swallows exceptions and prints them; a partial run can leave gaps without a non-zero exit, so CI won't flag missing assets.
- **No tests.** There is no test suite for the toolchain.
- **No checksum verification** of downloaded assets.

> [!NOTE]
> The AST-level extraction over this repo finds only ~4 functions and 6 NamedTuple classes total — an accurate reflection that the codebase *is* small. The five-million-file scale is entirely generated output, not logic.

---

## 11. Potential Improvements

- [ ] **De-duplicate the two generators.** Extract shared `Asset`/`Fetch`/`Icon`, `_pattern_args`, `_fetch_fonts`, and version-ledger logic into a common module imported by both.
- [ ] **Refresh dependencies.** Bump `requests`, `urllib3`, `certifi`, `fonttools`, and drop the pinned `black==19.10b0` pre-release; the 2020-era pins carry known CVEs even if not exploitable here.
- [ ] **Harden ZIP extraction.** Replace bare `extractall()` with a guarded extraction that rejects path-traversal entries.
- [ ] **Fail loudly.** Make `update_symbols.py` track fetch failures and exit non-zero (or at least summarize failures) so CI surfaces partial runs.
- [ ] **Wire the classic generator (or document why not).** CI only runs `update_symbols.py`; if the classic set is permanently frozen, state that in the workflow comment so it's not mistaken for an omission.
- [ ] **Add a smoke test.** A tiny test (e.g. `icons.py` against a bundled sample font) would guard the most reusable component.
- [ ] **Configurable concurrency.** Hoist `n_jobs=50` and the axis lists into flags/constants instead of magic numbers.
- [ ] **Checksum/size sanity checks** before writing downloaded bytes.

> [!NOTE]
> These are observations about the *toolchain*. Most consumers never touch it — for them, the operational improvement that matters most is **pinning a snapshot** rather than tracking weekly-regenerated `master`.

---

## 12. Quick Reference

### Toolchain commands

| Task | Command (run from `update/`) |
|---|---|
| Dry-run classic | `python update_repo.py --nofetch` |
| Test classic (5 icons) | `python update_repo.py --icon_limit 5` |
| Full classic refresh | `python update_repo.py` |
| Skip existing classic | `python update_repo.py --skip_existing` |
| Dry-run symbols | `python update_symbols.py --nofetch` |
| Test symbols (5 icons) | `python update_symbols.py --icon_limit 5` |
| Force-overwrite symbols | `python update_symbols.py --overwrite` |

### Upstream endpoints

| Endpoint | Used by |
|---|---|
| `fonts.google.com/metadata/icons?incomplete=1` | `update_repo.py` (classic metadata) |
| `fonts.google.com/metadata/icons?incomplete=1&key=material_symbols` | `update_symbols.py` (symbols metadata) |
| `{host}/s/i/...` | per-asset SVG/zip/xml downloads |
| `fonts.googleapis.com/css2?family=...` | font CSS → binary resolution |

### Generated output directories

| Directory | Set | Format |
|---|---|---|
| `src/` | Classic | SVG (24px) |
| `png/` | Classic | PNG (18–48dp, 1x/2x/3x) |
| `android/` | Classic | Vector XML + density PNG |
| `ios/` | Classic | `.xcassets` imagesets |
| `font/` | Classic | `.otf`/`.ttf` + `.codepoints` |
| `symbols/web|android|ios/` | Current | SVG / XML / SVG per variant |
| `variablefont/` | Current | `.ttf`/`.woff2` + `.codepoints` |

### CI summary

| Property | Value |
|---|---|
| File | `.github/workflows/main.yml` |
| Trigger | `workflow_dispatch` + cron `0 2 * * 5` (Fri 02:00 UTC) |
| Runs | `update_symbols.py` only |
| Python | 3.11 |
| Output | Commits regenerated symbols assets to `master` |

### Facts & negative knowledge

- There is **no** application server, API, or database in this repository.
- There is **no** global version number; versioning is per-icon via `current_versions.json`.
- CI does **not** run `update_repo.py` (classic generator); only `update_symbols.py`.
- Material **Symbols** iOS assets have **no** weight (`wght`) variants — only fill/grade.
- Material **Icons** (classic) has **no** variable axes and **no** two-tone in the Symbols set.
- Google does **not** accept pull requests for icon files.

---

_Generated June 2026 from google/material-design-icons at fef175f. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
