Regenerate the icons
Edit the icon master sheet, then export it into libres with three qbs commands
Regenerate the icons
content/design/icons.svg is the icon master. Every icon under
src/libs/libres/resources/icons/ is cut out of that one file by the
icon-export tool. The folder is generated output.
Do not hand-edit a file under src/libs/libres/resources/icons/. The next
export overwrites it. Edit the master instead.
The whole routine
Run these three commands from the repository root:
qbs run -p icon-export -- content/design/icons.svg --auto-tag --retag-drift --apply
qbs run -p icon-export -- content/design/icons.svg --align-grid --apply
qbs run -p icon-export -- content/design/icons.svg src/libs/libres/resources/icons
Then review the result and build:
git status --short
qbs resolve --force-probe-execution
qbs build
The forced probe is necessary. The icon bundle is a glob, so a new file stays invisible to the build until the probe runs again.
What each command does
- Auto-tag. Each icon on the sheet is a 64x64 rect. The tool reads the
column header above it and the title box beside it, then writes the id
cutout--<column>--<title>. That id becomes the file path.--retag-driftalso rewrites ids whose sheet text changed. - Align-grid. The tool snaps every cutout box, every title box and their content to the 64px grid. Content moves with its box, so art never separates from its frame.
- Export. The tool writes one standalone SVG per cutout. It also deletes the files that earlier runs made and this run does not, so a renamed icon leaves no old copy behind.
Read the output
The export prints one summary line:
Exported: 373, Removed: 6, Errors: 0
If Errors is not 0, read the error lines above the summary. The tool refuses
to write an icon that would render blank, and it keeps the previous file in
that case. A blank icon is the failure this checks for. It has two causes:
- The cutout is a scaffold and nobody pasted art into it yet.
- The art references an element the tool cannot find.
If Removed is not 0, the sheet stopped making those icons. Search the code
for their old paths and repoint every reference in the same commit.
The build checks this for you
libres runs icon-export --check as a build rule on every native build. The
check writes nothing. It fails the build when an icon differs from the sheet,
is missing, or is left over from a cutout the sheet stopped making:
DRIFT: app/reload.svg differs from the sheet
Checked: 373, Drifted: 1, Errors: 0
The failure names every file and prints the export command. Run it. Do not edit the icon to make the message go away — the sheet decides the content, and the next export overwrites the edit.
A cross build prints one line saying the guard did not run. That is correct: the in-graph tool is a target-architecture binary there, and the check reads repository content that is the same for every target. One native build proves it for all of them.
Add an icon
- Open
content/design/icons.svgin Inkscape. - Copy an existing cutout unit. A unit is the 64x64 cutout rect plus the 256x64 title box beside it.
- Draw the art inside the cutout rect.
- Type the icon name into the title box.
- Save, then run the three commands above.
The column header names the folder and the title names the file. A title can
carry slashes, and the two compound: header llm with title
Providers/Subscription/Groq writes
opal/providers/subscription/groq.svg. A title must
never repeat its column name.
Add a mark that is not an icon
The grid holds 64x64 icons. A wordmark, a banner or a plate does not fit it, so the sheet has a second kind of cutout for art of any size at any position.
-
Draw the art anywhere in
content/design/icons.svg. It does not need a lane and it does not need a column banner. -
Draw a cutout rect around it. Any size.
-
Draw a label box to the right of the cutout, touching it or within 64 units of it, with the same vertical span. Put one text inside the box.
-
Select the cutout rect, press
Ctrl+Shift+X, and set itsidby hand:cutout-standalone--brand--octomy-logo-dark -
Save, then run the export command.
The id decides the path, exactly as it does for a grid icon: -- separates
folders and a single hyphen is part of a name, so the id above writes
brand/octomy-logo-dark.svg.
The label names the file for a person reading the sheet. A label with no slash
is checked against the last part of the id, so OctoMY Logo Dark matches the
id above. A label with a slash states the whole path, so Brand/OctoMY Logo Dark also matches.
The tool never creates one of these for you. A grid cutout is identified by
three facts — its size, its lane and its banner — and a standalone cutout has
none of them, so a rule that guessed would name random sheet furniture as
icons. You write the id once. --auto-tag then checks every standalone cutout
and reports what is wrong:
Standalone cutouts: 2 checked, 1 with something wrong
STANDALONE cutout-standalone--brand--octomy-logo-dark: the label 'OctoMY Logo Light' says cutout-standalone--brand--octomy-logo-light
--align-grid never moves a standalone unit, and never moves its art.
Rules
- Never author an icon file by hand. The set is curated by the owner. See AGENTS.md.
- Revert in Inkscape after every
--apply. The tool writes the master in place. If Inkscape holds a stale buffer and saves it, the tool's changes disappear. This happened once and cost a full re-run. - Never delete a file under the icons folder by hand. Delete the cutout from the sheet and export. The export removes the file.
window/app/<name>.svgis a packaging contract.App.qbsbuilds that path from the application name to make the Windows.ico, andintegration/editions/octomy/edition.jsonmaps the same files. A rename there breaks packaging with no error.- Five files in the icons folder do not come from the sheet:
app/view_grid.png,app/view_list.png,app/view_tree.png,octomy_logo_dark.svgandoctomy_logo_light.svg. The tool never generated them, so it never touches them. The list is the difference between the tracked files and.icon-export-manifest. Measure it, do not trust this line:
comm -23 <(git ls-files src/libs/libres/resources/icons | sed 's|.*/icons/||' \
| grep -E '\.(svg|png)$' | sort) \
<(grep -v '^#' src/libs/libres/resources/icons/.icon-export-manifest | sort)
Check every reference
The export cannot know which paths the code uses. After a rename, verify that every icon reference still resolves:
grep -rho ':/icons/[A-Za-z0-9_/.-]*\.\(svg\|png\)' src/ test/ \
| sort -u | sed 's|:/icons/||' \
| while read -r p; do
test -e "src/libs/libres/resources/icons/$p" || echo "MISSING: $p"
done
Five names are expected in the output of this check. Anything else is a real break:
arrow.pngandgroupbox.png—libstylekeeps its own private:/icons/bundle with those two files in it.swarm/chip/no-such-asset.svgandopal/providers/api/no-such-brand.svg— two tests ask for a missing icon on purpose. One proves the fallback works, the other is a negative control that stops its own checks from being vacuous. Both names are spelled in test source, so re-read them from the suites rather than trusting this list: it already went stale once, when the opal lane retired a duplicate guard and itsno-such-icon.svgwith it.fixo/fallback-template.svg— named inside a comment that explains the path never existed.