R8a: replace the default Python title bar icon with a Graphlink app mark - #168
Merged
Conversation
The window showed the Python interpreter's icon. That was never a design problem - it was a wiring one. pywebview's Windows backend falls back to extracting icon index 0 from sys.executable when no icon is passed (webview/platforms/winforms.py:245-250), and nothing in this repo ever passed one. assets/graphlink.ico existed but was referenced from exactly zero call sites. That file was also malformed for the job: a single 1024x1024 bitmap in an .ico container with no 16/24/32 frames, so every size Windows actually renders - title bar, taskbar, Alt-Tab - was brute-force downscaling a poster. Adds a real mark: a stem forking into two directed branches, drawn at one uniform stroke weight. Generated, not hand-drawn - tools/build_app_icon.py emits the canonical SVG, the multi-frame .ico and both favicons from a single geometry definition, so the vector and the bitmaps cannot drift apart. Eight frames, each rendered at its own size with the margin tuned per size rather than shrunk into place. Two things learned while tuning, both documented in the script and the branding README because they are counterintuitive: - Fattening strokes at small sizes made legibility WORSE, not better. The binding constraint is the chevron's aperture, and a heavier stroke closes it into a blob. Stroke is constant across sizes; only the margin varies. - The chevron angle has a narrow usable band. Too tight and the aperture closes; past ~80 degrees the arms splay and the pair reads as a flat zigzag instead of two arrows. Also wires the favicons, which had the same root cause: index.html declared no icon at all, so the browser's automatic /favicon.ico request fell through the SPA catch-all and got index.html back as text/html. The nine explored alternatives are kept under assets/branding/ as internal assets for docs, badges and splash art, with the palette and the canonical file documented so it does not become tribal knowledge. Icon shrinks from 911KB to 30KB while gaining seven frames.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the Python interpreter icon shown in the application title bar with a purpose-built Graphlink mark, and wires the previously-orphaned icon asset into both the desktop window and the browser tab.
Problem
The desktop window displayed the Python interpreter's icon.
pywebview's Windows backend extracts icon index 0 fromsys.executablewhen no icon is supplied (webview/platforms/winforms.py:245-250), andgraphlink_desktop.pynever supplied one. The existingassets/graphlink.icohad no references anywhere in the codebase.That asset was additionally unsuitable for the role: a single 1024×1024 frame in an
.icocontainer with no 16/24/32 px variants, requiring Windows to downscale one large bitmap for every size it actually renders — title bar, taskbar, and Alt-Tab.The browser tab was affected by the same omission.
index.htmldeclared no icon, so the browser's implicit/favicon.icorequest fell through the SPA catch-all route and receivedindex.htmlwithContent-Type: text/html.Changes
Icon generation.
tools/build_app_icon.pyproduces the canonical SVG, the multi-frame.ico, and both favicon formats from a single geometry definition, preventing drift between vector and raster sources. The.icocontains eight frames (16–256 px), each rendered independently at its target size with per-size margin tuning rather than downscaled from one bitmap.Stroke width is held constant across all sizes. Increasing stroke weight at small sizes — the conventional approach to pixel alignment — closes the aperture between the chevron arms and degrades legibility; margin is therefore the only per-size variable. Both constraints are documented in the script and in
assets/branding/README.md.Desktop window.
graphlink_desktop.pypassesicon=towebview.start(), guarded on file existence and logging a warning rather than raising if the asset is missing.Browser tab.
index.htmldeclares an SVG icon with an.icofallback, both served verbatim fromweb_ui/src/app/public/.Design assets. Nine alternative concepts are retained under
assets/branding/for documentation, badges, and splash art, with the palette and canonical file recorded in the accompanying README.assets/graphlink.icodecreases from 911 KB to 30 KB while gaining seven frames.Verification
tsc --noEmit/ ESLint / tests / build.icoload viaSystem.Drawing.Icon(the call pywebview makes)/favicon.svg200 image/svg+xml/favicon.ico200 image/x-icon(previously returned HTML)A 256 px request returns the 128 px frame, a known GDI+ constraint that does not affect title bar or taskbar rendering. All frames were inspected at 1:1 and magnified against both light and dark title bars.
Outstanding
The icon has not been confirmed in a running desktop window. The loading mechanism is verified end to end, but visual confirmation in the live title bar is recommended before merge.