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)

Files