variations.py
In source/
Preview
Code5.3 KiB"""Alternate logo arrangements built from the approved contours."""
from copy import deepcopy
from pathlib import Path
import subprocess
import xml.etree.ElementTree as E
from .logo import render, NS, element
from .design import UNO_BLUE
OPTIONS = [
('01-classic-grid','Classic / fading grid','Original proportions and square frame'),
('02-blue-reverse','Blue / white lettering','Full color solids on Uno blue'),
('03-rounded-frame','Rounded / open frame','Soft frame with the original composition'),
('04-rounded-blue','Rounded / blue field','White lettering in a rounded blue container'),
('05-wordmark-blue','Wordmark / blue','Wide KIT lettering without the illustration'),
('06-wordmark-reverse','Wordmark / reverse','White lettering on an Uno-blue field'),
('07-horizontal','Horizontal / full color','Geometric symbol paired with the wordmark'),
('08-compact','Compact / rounded tile','A simple wordmark for smaller placements'),
('09-monochrome','Monochrome / reverse','White solids with blue construction edges'),
]
def variant(index):
root=E.fromstring(render(grid=index==0))
children=list(root)
bg=next(e for e in children if e.tag==NS+'rect')
solids=next(e for e in children if e.tag==NS+'svg')
frame=next(e for e in children if e.tag==NS+'path' and e.get('fill')=='none')
letters=children[-3:]
blue=index in [1,3,5,7,8]
if blue:
bg.set('fill',UNO_BLUE)
for e in letters:e.set('fill','white')
frame.set('stroke','white')
if index in [2,3,7,8]:
root.remove(frame)
if index==2:
E.SubElement(root,NS+'rect',{'x':'3.35','y':'3.35','width':'73.3','height':'73.3','rx':'7','fill':'none','stroke':UNO_BLUE,'stroke-width':'1.682'})
else:
bg.set('rx','9')
if index in [1,3]:
sphere=next(e for e in solids if e.get('aria-label')=='Sphere')
circle=next(iter(sphere))
# A fine keyline preserves the blue sphere silhouette against the blue field.
rim=deepcopy(circle)
rim.attrib.update({'fill':'none','stroke':'white','stroke-width':'1.8','stroke-opacity':'.7'})
sphere.append(rim)
if index in [4,5]:
root.remove(solids)
root.remove(frame)
root.set('viewBox','0 0 80 38')
bg.set('height','38')
for e in letters:e.set('transform','translate(0 -41.5)')
if index==6:
root.remove(frame)
root.set('viewBox','0 0 154 60')
bg.set('width','154');bg.set('height','60')
solids.set('x','-2');solids.set('y','3')
for e in letters:e.set('transform','translate(75 -30.5)')
if index==7:
root.remove(solids)
for e in letters:e.set('transform','translate(6.4 -21) scale(.84)')
if index==8:
for e in solids.iter():
if e.tag in [NS+'path',NS+'circle']:
e.set('fill','white');e.set('stroke',UNO_BLUE)
e.set('stroke-width','2.4');e.set('stroke-linejoin','round')
# Remove unused gradients for lightweight exports.
defs=root.find(NS+'defs')
used=' '.join(v for e in root.iter() if e is not defs for v in e.attrib.values())
for e in list(defs):
if 'url(#'+e.get('id','')+')' not in used:defs.remove(e)
title=root.find(NS+'title');title.text='KIT — '+OPTIONS[index][1]
root.find(NS+'desc').text=OPTIONS[index][2]
root.set('width','1000');root.set('height','1000')
if index in [4,5]:root.set('width','1400');root.set('height','665')
if index==6:root.set('width','1540');root.set('height','600')
return root
def build(root):
art=root/'art'/'variations';art.mkdir(parents=True,exist_ok=True)
previews=root/'previews'/'variations';previews.mkdir(parents=True,exist_ok=True)
sheet=E.Element(NS+'svg',{'width':'1920','height':'2016','viewBox':'0 0 1920 2016'})
element(sheet,'rect',width=1920,height=2016,fill='#f3f5f8')
element(sheet,'text',x=48,y=64,fill='#0067ed',font_family='Helvetica, Arial, sans-serif',font_size=30,font_weight=700).text='KIT / Brand variations'
element(sheet,'text',x=48,y=98,fill='#536174',font_family='Helvetica, Arial, sans-serif',font_size=17).text='Uno blue · original geometry · wide lettering'
for i,(name,title,description) in enumerate(OPTIONS):
svg=variant(i)
path=art/(name+'.svg');path.write_text(E.tostring(svg,encoding='unicode'))
subprocess.run(['rsvg-convert','-o',str(previews/(name+'.png')),str(path)],check=True)
x=48+(i%3)*624;y=136+(i//3)*624
element(sheet,'rect',x=x,y=y,width=600,height=600,rx=16,fill='white')
nested=deepcopy(svg)
nested.attrib.update({'x':str(x+44),'y':str(y+28),'width':'512','height':'470'})
# Prefix paint IDs in the sheet so each cell owns its gradients.
ids={e.get('id'):f'v{i}-'+e.get('id') for e in nested.iter() if e.get('id')}
for e in nested.iter():
for key,value in list(e.attrib.items()):
if key=='id':e.set(key,ids[value])
elif key=='aria-labelledby':e.set(key,' '.join(ids.get(v,v) for v in value.split()))
else:
for old,new in ids.items():value=value.replace('url(#'+old+')','url(#'+new+')')
e.set(key,value)
sheet.append(nested)
element(sheet,'text',x=x+28,y=y+539,fill='#0067ed',font_family='Helvetica, Arial, sans-serif',font_size=20,font_weight=700).text=f'{i+1:02} {title}'
element(sheet,'text',x=x+28,y=y+570,fill='#536174',font_family='Helvetica, Arial, sans-serif',font_size=15).text=description
path=art/'comparison.svg';path.write_text(E.tostring(sheet,encoding='unicode'))
subprocess.run(['rsvg-convert','-o',str(previews/'comparison.png'),str(path)],check=True)
print('Built nine SVG and PNG variations plus comparison sheet.')
if __name__=='__main__':build(Path(__file__).resolve().parent.parent)