# -*- coding: utf-8 -*-
import base64, os
FONTS = r"C:\Users\nk\.claude\skills\canvas-design\canvas-fonts"
OUT = r"C:\radiOLA\design\logos"
def b64(p):
with open(p, "rb") as f:
return base64.b64encode(f.read()).decode()
erica = b64(os.path.join(FONTS, "EricaOne-Regular.ttf"))
outfit = b64(os.path.join(FONTS, "Outfit-Bold.ttf"))
FONT_CSS = f"""
@font-face {{ font-family:'Erica'; src:url(data:font/ttf;base64,{erica}) format('truetype'); }}
@font-face {{ font-family:'Outfit'; src:url(data:font/ttf;base64,{outfit}) format('truetype'); }}
"""
# Изометрическая экструзия вниз-вправо: сочная зелёная боковая грань (как материал в тени)
def extr(steps=18, dx=1.0, dy=1.1):
parts=[]
for i in range(1, steps+1):
t=i/steps
# грань — насыщенный зелёный, плавно темнеющий ко дну (не чёрный)
r=int(0x52-0x22*t); g=int(0x8c-0x40*t); b=int(0x2c-0x14*t)
parts.append(f"{dx*i:.1f}px {dy*i:.1f}px 0 rgb({r},{g},{b})")
parts.append(f"{dx*steps+6:.0f}px {dy*steps+12:.0f}px 22px rgba(0,0,0,.5)") # контактная тень
return ",".join(parts)
EXTR = extr()
GLOW = "#C2F25B"
def motif_broadcast():
cx,cy=408,116; arcs=""
for i,r in enumerate([36,66,98]):
op=0.95-0.22*i
arcs+=f''
return f''
def motif_wave():
hs=[28,58,96,134,168,134,96,168,120,70,36]; bw=22; gap=11
total=len(hs)*(bw+gap)-gap; x0=(512-total)/2; base=452
grad=''
bars=""
for i,h in enumerate(hs):
x=x0+i*(bw+gap)
bars+=f''
return f''
def motif_vinyl():
cx,cy=132,372; grooves=""
disc=f''
for r in range(128,44,-15):
grooves+=f''
label=f''
shine=f''
return f''
def motif_antenna():
x,y=398,158
mast=f''.replace("ef","ef")
mast=f''
waves=""
for i,r in enumerate([30,52,76]):
op=0.9-0.22*i; sw=8-2*i
waves+=f''
waves+=f''
tip=f''
return f''
def motif_tuner():
y=452; x0=92; x1=420; n=23; ticks=""
for i in range(n):
x=x0+(x1-x0)*i/(n-1); big=(i%4==0); h=24 if big else 13
ticks+=f''
base=f''
kx=x0+(x1-x0)*0.63
knob=f''
return f''
VARIANTS = [
("01","Эфир","дуги вещания",motif_broadcast(),0),
("02","Волна","эквалайзер",motif_wave(),-26),
("03","Винил","пластинка + R",motif_vinyl(),-6),
("04","Антенна","вышка + сигнал",motif_antenna(),6),
("05","Тюнер","частотная шкала",motif_tuner(),-30),
]
def tile(motif, shift_y):
return f"""
"""
TILE_CSS = f"""
*{{margin:0;padding:0;box-sizing:border-box}}
{FONT_CSS}
.tile{{position:relative;width:512px;height:512px;overflow:hidden;border-radius:22.5%;background:#0c1410}}
.bg{{position:absolute;inset:0;background:radial-gradient(125% 105% at 50% -5%, #1a2c1d 0%, #0e1712 50%, #060c08 100%);}}
.glow{{position:absolute;left:48%;top:46%;width:88%;height:88%;transform:translate(-50%,-50%);
background:radial-gradient(circle, rgba(176,236,98,.42) 0%, rgba(140,210,70,.12) 38%, rgba(168,224,95,0) 64%);}}
.rwrap{{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}}
.r{{font-family:'Erica';font-size:284px;line-height:.78;
background:
linear-gradient(176deg, rgba(255,255,255,.72) 0%, rgba(255,255,255,.16) 22%, rgba(255,255,255,0) 40%),
linear-gradient(150deg,#F0FFAE 0%,#CFF96E 24%,#B3EC5E 46%,#9BD94F 68%,#84C53F 100%);
-webkit-background-clip:text;background-clip:text;color:transparent;
text-shadow:{EXTR};}}
"""
for num,name,sub,motif,sy in VARIANTS:
html=f"""
{tile(motif,sy)}"""
open(os.path.join(OUT,f"icon_{num}.html"),"w",encoding="utf-8").write(html)
cards=""
for num,name,sub,motif,sy in VARIANTS:
cards+=f""""""
sheet=f"""
radiOLA
5 концепций знака · объёмная «R» · радио-мотив
Lumen Relay
{cards}
"""
open(os.path.join(OUT,"sheet.html"),"w",encoding="utf-8").write(sheet)
print("ok")