feat(store): branded feature graphic (1024x500) + 512 store icon

Noto Sans wordmark on brand green (#2F7D34), white sprout, and the official
value tagline ('keep and share traditional seeds' / 'guarda y comparte...').
Generated by tool/gen_feature_graphic.py for en-US and es-ES.
This commit is contained in:
vjrj 2026-07-16 02:49:06 +02:00
parent fd6b9d5f0d
commit eef99975bf
5 changed files with 101 additions and 0 deletions

View file

@ -0,0 +1,101 @@
#!/usr/bin/env python3
"""Generate Play Store feature graphics (1024x500) + store icon (512) for Tane.
Brand green #2F7D34, white sprout from the adaptive foreground, 'Tane' wordmark
in Noto Sans (the site's brand typeface), and the official value-proposition
tagline. On-brand and replaceable with a designed asset later.
Run from apps/app_seeds/: python3 tool/gen_feature_graphic.py
"""
import os
from PIL import Image, ImageDraw, ImageFont
REPO_APP = "/home/vjrj/proyectos/dev/tane/.claude/worktrees/interesting-cray-6261fd/apps/app_seeds"
NOTO = "/usr/share/fonts/truetype/noto"
F_BOLD = f"{NOTO}/NotoSans-Bold.ttf"
F_MED = f"{NOTO}/NotoSans-Medium.ttf"
F_REG = f"{NOTO}/NotoSans-Regular.ttf"
FG = f"{REPO_APP}/assets/icon_foreground.png"
ICON = f"{REPO_APP}/assets/icon.png"
GREEN = (47, 125, 52) # #2F7D34
GREEN_DARK = (34, 82, 30) # #22521E
WHITE = (255, 255, 255)
FAINT = (208, 228, 210)
W, H = 1024, 500
# value line = what the app is (explains it); attrs = the differentiators.
COPY = {
"en-US": ("Keep and share traditional seeds", "Offline · Encrypted · No account"),
"es-ES": ("Guarda y comparte semillas tradicionales", "Sin conexión · Cifrado · Sin cuenta"),
}
def sprout(height):
im = Image.open(FG).convert("RGBA")
bb = im.getbbox()
if bb:
im = im.crop(bb)
s = height / im.height
return im.resize((max(1, int(im.width * s)), height), Image.LANCZOS)
def bg():
top = Image.new("RGB", (W, H), GREEN)
bot = Image.new("RGB", (W, H), GREEN_DARK)
mask = Image.new("L", (W, H))
md = ImageDraw.Draw(mask)
for y in range(H):
md.line([(0, y), (W, y)], fill=int(60 * (y / H)))
return Image.composite(bot, top, mask)
def center_line(d, text, font, top, fill):
b = d.textbbox((0, 0), text, font=font)
w = b[2] - b[0]
d.text(((W - w) / 2 - b[0], top - b[1]), text, font=font, fill=fill)
return b[3] - b[1]
def feature_graphic(locale, out):
img = bg()
d = ImageDraw.Draw(img)
value, attrs = COPY[locale]
# Row 1: sprout + 'Tane', centered as a group in the upper half.
spr = sprout(150)
wf = ImageFont.truetype(F_BOLD, 120)
wb = d.textbbox((0, 0), "Tane", font=wf)
ww, wh = wb[2] - wb[0], wb[3] - wb[1]
gap = 26
gw = spr.width + gap + ww
gx = (W - gw) // 2
row_top = 92
cy = row_top + spr.height / 2
img.paste(spr, (gx, row_top), spr)
d.text((gx + spr.width + gap - wb[0], cy - wh / 2 - wb[1]), "Tane", font=wf, fill=WHITE)
y = row_top + spr.height + 34
# Row 2: value proposition (explains the app).
vf = ImageFont.truetype(F_MED, 42)
y += center_line(d, value, vf, y, WHITE) + 18
# Row 3: differentiators, quieter.
af = ImageFont.truetype(F_REG, 30)
center_line(d, attrs, af, y, FAINT)
img.save(out, "PNG")
print("wrote", out, img.size)
def store_icon(out):
Image.open(ICON).convert("RGB").resize((512, 512), Image.LANCZOS).save(out, "PNG")
print("wrote", out)
for loc in ("en-US", "es-ES"):
d = f"{REPO_APP}/fastlane/metadata/android/{loc}/images"
os.makedirs(d, exist_ok=True)
feature_graphic(loc, f"{d}/featureGraphic.png")
store_icon(f"{d}/icon.png")