app_icons: add the bowl-star glyph for restaurant-rater
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run

A new app at ~/restaurant-rater rates restaurant dishes, so it needs a
family icon. shield-cutlery is diet-guard's and the accent is shared
fleet-wide, so the new glyph has to be distinguished by silhouette alone: a
filled star above an open bowl -- a dish, and a verdict on it.

The star is filled rather than stroked for the same reason as the nib and
the anvil: at 72px weight its five interior notches close up well above
MIN_NEGATIVE_SPACE and it renders as a pentagon at 48dp.

The bowl went through two passes. The first used shallow walls stopping at
y=736 and read unmistakably as a smiling mouth with the star for a nose --
two curves with a shape above them is a face unless the vessel is clearly
deeper than it is wide at the base. The committed version drops to y=752
between narrower walls, which reads as a bowl.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012YDbT3ip2yeT18W3KCZdLq
This commit is contained in:
Krzysztof Rudnicki 2026-08-29 17:18:16 +02:00
parent 61abbf8cf9
commit f70af95b61
4 changed files with 87 additions and 0 deletions

View File

@ -0,0 +1,45 @@
{
"intent": "Give the new ~/restaurant-rater app a launcher icon from the shared family, so it stops shipping the stock Flutter beach icon.",
"scope": [
"python_pkg/app_icons/_glyph_art_more.py - the new SVG fragment",
"python_pkg/app_icons/glyphs.py - register the glyph in GLYPHS",
"python_pkg/app_icons/apps.py - register the app so --app restaurant_rater passes argument validation",
"Non-goal: no change to the shared accent #B8862E or the charcoal field; a glyph is distinguished by silhouette only",
"Non-goal: no change to any existing app's icon"
],
"changes": [
"Added _BOWL_STAR: a filled five-pointed star (R=140 r=56 about 512,380) above an open bowl with a rim at y=566 and walls dropping to y=752. Total ink y=240..788, inside the 560 safe box.",
"The star is filled rather than stroked, for the same reason as _QUILL_NIB and _ANVIL: at STROKE_WIDTH=72 its five interior notches close below MIN_NEGATIVE_SPACE and render as a pentagon at 48dp.",
"Registered Glyph('bowl-star', ...) in GLYPHS and AppIcon(key='restaurant_rater', glyph='bowl-star', linux=False) in APPS."
],
"verification": [
{
"command": "PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons list",
"result": "pass",
"evidence": "bowl-star appears under Glyphs; 'restaurant_rater #B8862E bowl-star /home/kuhy/restaurant-rater' appears under Apps."
},
{
"command": "PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons generate --app restaurant_rater",
"result": "pass",
"evidence": "wrote 6 asset files to /home/kuhy/restaurant-rater/assets/icon (icon/foreground/monochrome, svg+png each). The generator's safe-box and negative-space checks did not fire."
},
{
"command": "visual review of the rendered 640px icon.png",
"result": "pass",
"evidence": "First render read as a smiling face - shallow bowl walls stopping at y=736 became a mouth with the star for a nose. Deepened to y=752 between narrower walls (348/676) and re-rendered; it now reads as a bowl with a rim. Recorded in the fragment's comment so the next reader does not undo it."
},
{
"command": "pre-commit run --files python_pkg/app_icons/glyphs.py python_pkg/app_icons/apps.py python_pkg/app_icons/_glyph_art_more.py",
"result": "pass",
"evidence": "mypy, pylint 10.00/10, bandit, pytest with coverage enforcement, 250-line cap and codespell all pass. An earlier run failed pylint C0301 on a 111-char comment line; the comment was rewrapped rather than suppressed."
}
],
"risks": [
"The glyph is new artwork, so only a visual check can confirm it reads correctly at 48dp. Mitigated by rendering and reviewing the actual PNG rather than trusting the SVG source.",
"_glyph_art_more.py grew to 127 lines; it and _glyph_art.py exist solely to stay under the 250-line cap, so a third file will be needed eventually."
],
"rollback": [
"git revert the commit. The three edits are additive - no existing glyph, app or shared token is touched - so a revert cannot change any other app's icon.",
"After rollback, re-run 'python3 -m python_pkg.app_icons list' and confirm the remaining 15 glyphs still resolve, then regenerate any app whose icon was rebuilt in the meantime."
]
}

View File

@ -99,3 +99,34 @@ M 392 646 A 30 30 0 0 0 392 706 A 30 30 0 0 0 392 646 Z \
M 500 356 L 652 356 L 652 396 L 500 396 Z \
M 500 496 L 652 496 L 652 536 L 500 536 Z \
M 500 636 L 652 636 L 652 676 L 500 676 Z"/>"""
# A filled five-pointed star sitting above an open bowl: a dish, and a verdict
# on it. Distinct from _SHIELD_CUTLERY (diet-guard) by silhouette rather than
# colour -- the accent is shared family-wide and must not carry meaning.
#
# The star is FILLED, not stroked, for the nib/anvil reason: at 72px weight an
# outlined star's five interior notches close up well above
# MIN_NEGATIVE_SPACE and render as a pentagon blob at 48dp.
#
# Geometry, all inside SAFE_BOX (x=232..792, y=232..792):
# star R=140 r=56 about (512,380): spans y=240..493, x=379..645
# rim y=566, x=268..756 -- stroke top 530, so 37px clear of the star's
# lowest point at 493, just above MIN_NEGATIVE_SPACE=36
# bowl walls at x=348 and x=676 dropping to y=752: stroke bottom 788,
# 4px inside the safe box
#
# The bowl is deep and narrow relative to its rim on purpose. A first pass
# used shallow walls at x=330..694 stopping at y=736, and the result read as
# a smiling mouth with the star for a nose -- two curves and a shape above
# them is a face unless the vessel is unmistakably deeper than it is wide at
# the base. Total ink runs y=240..788 = 548, under the 560 safe box.
#
# The star's lowest points are the two lower
# outer tips at y=493 -- NOT the inner vertex at y=436, which is what a first
# pass measured before checking; the rim was placed off that and overlapped
# the tips. Compute every extreme, do not eyeball one.
_BOWL_STAR = """\
<path d="M 512 240 L 545 335 L 645 337 L 565 397 L 594 493 L 512 436 \
L 430 493 L 459 397 L 379 337 L 479 335 Z" fill="{{ACCENT}}" stroke="none"/>
<path d="M 268 566 L 756 566"/>
<path d="M 348 566 C 348 700 420 752 512 752 C 604 752 676 700 676 566"/>"""

View File

@ -118,6 +118,15 @@ APPS: Final[dict[str, AppIcon]] = {
# Android-only app: no GTK desktop build to hand a hicolor PNG to.
linux=False,
),
AppIcon(
key="restaurant_rater",
repo=_HOME / "restaurant-rater",
accent="#B8862E",
glyph="bowl-star",
icon_name="restaurant-rater",
# Android-only app: no GTK desktop build to hand a hicolor PNG to.
linux=False,
),
AppIcon(
key="habit_stack",
repo=_HOME / "habit_stack",

View File

@ -30,6 +30,7 @@ from python_pkg.app_icons._glyph_art import (
_STORAGE_BOX,
)
from python_pkg.app_icons._glyph_art_more import (
_BOWL_STAR,
_NOTE_ASCENDER,
_PADLOCK_CLOSED,
_PUNCH_CARD,
@ -85,6 +86,7 @@ GLYPHS: Final[dict[str, Glyph]] = {
"Closed padlock with a punched-out keyhole",
_PADLOCK_CLOSED,
),
Glyph("bowl-star", "Filled star above an open bowl", _BOWL_STAR),
)
}