Sign in

vitor-internCopy the usernamekit-logo-remix-remix

shapes.py

In source/

mainHistory

Preview

Code5.1 KiB
"""Individual solids and symbol treatments from the canonical logo geometry."""
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

SHAPES=['sphere','pyramid','cube','cylinder']
BOUNDS={'sphere':(-382.5,-244.25799,-147.5,-9.25799),'pyramid':(-232.5,-375,82.5,-66.25),'cube':(-82.5,-235.34,187.5,65),'cylinder':(162.5,-382.5,372.5,-45)}
STYLES=['Gradient','Flat faces','Uno tonal','Blue outline','White reverse','Color on blue']
COLORS={'pyramid':['#ff6552','#ef3c3c'],'cylinder':['#13b856','#36d76c','#79e58c'],'sphere':['#0067ed','#319eff'],'cube':['#ffed72','#edbc17','#f6d52e']}

def make(shape,style):
 original=E.fromstring(render(False))
 root=E.Element(NS+'svg',{'width':'800','height':'800','viewBox':'0 0 320 320','role':'img','aria-labelledby':'title desc'})
 element(root,'title',id='title').text='KIT '+(shape.title() if shape else 'shape composition')+' / '+STYLES[style]
 element(root,'desc',id='desc').text='Geometric KIT artwork without lettering. '+STYLES[style]+'.'
 defs=deepcopy(original.find(NS+'defs'));root.append(defs)
 if style>=4:element(root,'rect',width=320,height=320,rx=32,fill=UNO_BLUE)
 scene=original.find(NS+'svg')
 if shape:
  x0,y0,x1,y1=BOUNDS[shape]
  outer=element(root,'g',transform=f'translate({160-(x0+x1)*.325} {263-y1*.65}) scale(.65)')
  outer.append(deepcopy(next(g for g in scene if g.get('aria-label').lower()==shape)))
 else:
  outer=element(root,'svg',x=20,y=34,width=280,height=252,viewBox='-430 -430 860 560')
  for g in scene:outer.append(deepcopy(g))
 for g in list(outer):
  name=g.get('aria-label').lower()
  faces=[e for e in g if e.tag in [NS+'path',NS+'circle']]
  for i,e in enumerate(faces):
   if style==1:
    e.set('fill',COLORS[name][i%len(COLORS[name])]);e.attrib.pop('stroke',None)
   elif style==2:
    tones={'pyramid':['#319eff','#0052c0'],'cylinder':['#0052c0','#0067ed','#8acbff'],'sphere':['#0067ed','#8acbff'],'cube':['#8acbff','#0052c0','#319eff']}
    e.set('fill',tones[name][i%len(tones[name])]);e.attrib.pop('stroke',None)
   elif style in [3,4]:
    e.set('fill','white');e.set('stroke',UNO_BLUE);e.set('stroke-width','3.5');e.set('stroke-linejoin','round')
   if style==5:
    e.set('stroke','white');e.set('stroke-width','1.4');e.set('stroke-linejoin','round')
 # Keep only gradients referenced by this asset.
 used=' '.join(v for e in outer.iter() for v in e.attrib.values())
 for d in list(defs):
  if 'url(#'+d.get('id','')+')' not in used:defs.remove(d)
 return root

def embed(sheet,asset,x,y,w,h,prefix):
 nested=deepcopy(asset);nested.attrib.update(x=str(x),y=str(y),width=str(w),height=str(h))
 ids={e.get('id'):prefix+e.get('id') for e in nested.iter() if e.get('id')}
 for e in nested.iter():
  for k,v in list(e.attrib.items()):
   if k=='id':v=ids[v]
   elif k=='aria-labelledby':v=' '.join(ids.get(a,a) for a in v.split())
   else:
    for old,new in ids.items():v=v.replace('url(#'+old+')','url(#'+new+')')
   e.set(k,v)
 sheet.append(nested)

def write(root,name,svg):
 art=root/'art'/'shapes';previews=root/'previews'/'shapes'
 art.mkdir(parents=True,exist_ok=True);previews.mkdir(parents=True,exist_ok=True)
 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)

def board(width,height,title,subtitle):
 s=E.Element(NS+'svg',{'width':str(width),'height':str(height),'viewBox':f'0 0 {width} {height}'})
 element(s,'rect',width=width,height=height,fill='#f3f5f8')
 element(s,'text',x=40,y=52,fill=UNO_BLUE,font_family='Helvetica, Arial, sans-serif',font_size=28,font_weight=700).text=title
 element(s,'text',x=40,y=84,fill='#536174',font_family='Helvetica, Arial, sans-serif',font_size=16).text=subtitle
 return s

def build(root):
 sheet=board(1680,1430,'KIT / Shape library','Four solids · six treatments · shared geometry')
 for j,style in enumerate(STYLES):
  x=40+j*268
  element(sheet,'text',x=x+8,y=134,fill=UNO_BLUE,font_family='Helvetica, Arial, sans-serif',font_size=17,font_weight=700).text=f'{j+1:02} / {style}'
  for i,name in enumerate(SHAPES):
   y=155+i*310
   element(sheet,'rect',x=x,y=y,width=252,height=292,rx=14,fill='white')
   svg=make(name,j);write(root,f'{name}-{j+1:02}',svg)
   embed(sheet,svg,x+16,y+6,220,248,f'{name}-{j}-')
   element(sheet,'text',x=x+18,y=y+273,fill='#536174',font_family='Helvetica, Arial, sans-serif',font_size=16).text=name.title()
 write(root,'shape-library',sheet)
 groups=board(1680,1230,'KIT / Symbols without lettering','The original composition in six complementary treatments')
 for j,style in enumerate(STYLES):
  x=40+(j%3)*548;y=118+(j//3)*548
  element(groups,'rect',x=x,y=y,width=512,height=512,rx=16,fill='white')
  svg=make(None,j);write(root,f'composition-{j+1:02}',svg)
  embed(groups,svg,x+38,y+14,436,436,f'group-{j}-')
  element(groups,'text',x=x+25,y=y+483,fill=UNO_BLUE,font_family='Helvetica, Arial, sans-serif',font_size=20,font_weight=700).text=f'{j+1:02} / {style}'
 write(root,'symbol-library',groups)
 print('Built 24 individual shapes, six compositions, and two comparison sheets.')

if __name__=='__main__':build(Path(__file__).resolve().parent.parent)

Files

Loading files

Details

Size
5.1 KiB (5,261 bytes)
Object ID
e91ae3d…fb1Copy the object ID
  • AGENTS.md
  • README.md
  • build.py
  • cover.png
  • manifest.json
Size
5.1 KiB (5,261 bytes)
Object ID
e91ae3d…fb1Copy the object ID
Storage
Stored as one object
Size
5.1 KiB (5,261 bytes)
Object ID
e91ae3d…fb1Copy the object ID
Storage
Stored as one object
Verification