658a8541e9
SamiOS CI / lint-and-test (push) Successful in 14s
Major update adding full desktop environment support, complete branding suite, and project infrastructure: Desktop (WSL): - KDE Plasma + SDDM + Dolphin/Konsole/Kate/Firefox setup script - Windows 11 dark/light color schemes - PipeWire audio stack - WSLg-compatible launch script - SamiOS CLI tool (v0.2.0) with desktop command Branding: - Logos: face-on-pyramid with and without text (500px) - Icons: square + launcher (256/512/1024px) + SVG vector - Wallpapers: 1920x1080, 4K, clean variant (PIL-generated) - GRUB theme: full cobalt blue (#1424CE) theme with pyramid background - SDDM theme: SamiOS login screen configuration - Branding README with palette, typography, usage guidelines Fonts: - Sami Grotesk (Helvetica-like) as default system/UI font - Sami Sans as secondary - Full Sami font family support (excluding 7777 personal branding) - fontconfig rules mapping Helvetica/Arial → Sami Grotesk - Font policy enforcement in samios CLI Infrastructure: - Automated installer (samios-installer.sh): partition, format, pacstrap, bootloader - PKGBUILD for samios-branding package - Test suite: shell tests for profiledef, packages, pacman.conf, CLI, font policy - Makefile: test, lint, check, build, clean targets - Gitea Actions CI workflow - Voice integration architecture document (SamiType × SamiOS) - Updated roadmap reflecting completed phases
140 lines
5.6 KiB
Python
140 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Generate SamiOS GRUB theme assets:
|
||
- background.png (1024×768 dark navy gradient + centered pyramid + "SamiOS" label)
|
||
- icons/*.png (pyramid boot-selection icons)
|
||
- fonts/*.pf2 (GRUB PFF2 font via grub-mkfont)
|
||
"""
|
||
import os
|
||
from PIL import Image, ImageDraw, ImageFilter, ImageFont
|
||
import subprocess
|
||
|
||
THEME_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
ICONS_DIR = os.path.join(THEME_DIR, "icons")
|
||
FONTS_DIR = os.path.join(THEME_DIR, "fonts")
|
||
for d in (ICONS_DIR, FONTS_DIR):
|
||
os.makedirs(d, exist_ok=True)
|
||
|
||
# ── Brand colors
|
||
COBALT = (0x14, 0x24, 0xCE) # #1424CE primary
|
||
LIGHT = (0x3B, 0x4E, 0xD8) # #3B4ED8 secondary
|
||
DARK_BG = (0x05, 0x0A, 0x1F) # very dark navy
|
||
DARK_BG2 = (0x0A, 0x14, 0x3A) # slightly lighter navy
|
||
TEXT_COL = (0xCC, 0xD4, 0xF5) # soft lavender-white for "SamiOS" label
|
||
|
||
import glob
|
||
def _find_font(name):
|
||
for pat in (f"/usr/share/fonts/TTF/{name}",
|
||
f"/usr/share/fonts/truetype/dejavu/{name}"):
|
||
hits = glob.glob(pat)
|
||
if hits:
|
||
return hits[0]
|
||
raise FileNotFoundError(f"Cannot find font: {name}")
|
||
|
||
DEJAVU_REG = _find_font("DejaVuSans.ttf")
|
||
DEJAVU_BOLD = _find_font("DejaVuSans-Bold.ttf")
|
||
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
# 1. Background image
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
def make_background():
|
||
W, H = 1024, 768
|
||
# Build vertical gradient
|
||
bg = Image.new("RGB", (W, H))
|
||
for y in range(H):
|
||
t = y / (H - 1)
|
||
r = int(DARK_BG[0] + (DARK_BG2[0] - DARK_BG[0]) * t)
|
||
g = int(DARK_BG[1] + (DARK_BG2[1] - DARK_BG[1]) * t)
|
||
b = int(DARK_BG[2] + (DARK_BG2[2] - DARK_BG[2]) * t)
|
||
for x in range(W):
|
||
bg.putpixel((x, y), (r, g, b))
|
||
|
||
# Soft radial glow behind pyramid
|
||
glow = Image.new("RGBA", (W, H), (0, 0, 0, 0))
|
||
gd = ImageDraw.Draw(glow)
|
||
gd.ellipse([512 - 280, 160, 512 + 280, 560], fill=LIGHT + (30,))
|
||
glow = glow.filter(ImageFilter.GaussianBlur(100))
|
||
bg = Image.alpha_composite(bg.convert("RGBA"), glow)
|
||
|
||
draw = ImageDraw.Draw(bg, "RGBA")
|
||
|
||
# Pyramid geometry
|
||
cx, peak_y = 512, 210
|
||
base_y = 510
|
||
half_w = 210
|
||
left_x = cx - half_w
|
||
right_x = cx + half_w
|
||
|
||
# Ground shadow (stacked semi-transparent ellipses for soft falloff)
|
||
sw = int(half_w * 1.3)
|
||
for i in range(14):
|
||
a = int(30 * (1 - i / 14))
|
||
draw.ellipse([cx - sw, base_y + 6 - i, cx + sw, base_y + 14 - i],
|
||
fill=COBALT + (a,))
|
||
|
||
# Right (shadow) face
|
||
draw.polygon([(cx, peak_y), (right_x, base_y), (cx, base_y)],
|
||
fill=COBALT + (255,))
|
||
# Left (lit) face
|
||
draw.polygon([(cx, peak_y), (cx, base_y), (left_x, base_y)],
|
||
fill=LIGHT + (255,))
|
||
|
||
# "SamiOS" text
|
||
font = ImageFont.truetype(DEJAVU_BOLD, 52)
|
||
text = "SamiOS"
|
||
bbox = draw.textbbox((0, 0), text, font=font)
|
||
tw = bbox[2] - bbox[0]
|
||
draw.text(((W - tw) // 2 - bbox[0], base_y + 40), text,
|
||
fill=TEXT_COL, font=font)
|
||
|
||
out = os.path.join(THEME_DIR, "background.png")
|
||
bg.convert("RGB").save(out)
|
||
print(f" ✓ background.png ({W}×{H})")
|
||
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
# 2. Icons (pyramid silhouettes at multiple sizes)
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
def make_icons():
|
||
for sz in (16, 24, 32, 48):
|
||
img = Image.new("RGBA", (sz, sz), (0, 0, 0, 0))
|
||
d = ImageDraw.Draw(img)
|
||
cx = sz // 2
|
||
peak = int(sz * 0.18)
|
||
base = int(sz * 0.80)
|
||
hw = int(sz * 0.34)
|
||
d.polygon([(cx, peak), (cx + hw, base), (cx, base)], fill=COBALT + (255,))
|
||
d.polygon([(cx, peak), (cx, base), (cx - hw, base)], fill=LIGHT + (255,))
|
||
img.save(os.path.join(ICONS_DIR, f"samios_{sz}.png"))
|
||
print(" ✓ icons/samios_{{16,24,32,48}}.png")
|
||
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
# 3. Fonts (PFF2 via grub-mkfont)
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
def make_fonts():
|
||
specs = [
|
||
# (ttf source, output name, size)
|
||
(DEJAVU_REG, "SamiOS-Regular-16", 16),
|
||
(DEJAVU_BOLD, "SamiOS-Bold-16", 16),
|
||
(DEJAVU_REG, "SamiOS-Regular-12", 12),
|
||
(DEJAVU_BOLD, "SamiOS-Bold-14", 14),
|
||
]
|
||
for ttf, name, size in specs:
|
||
out = os.path.join(FONTS_DIR, f"{name}.pf2")
|
||
subprocess.run(
|
||
["grub-mkfont",
|
||
"--output", out,
|
||
"--size", str(size),
|
||
"--range", "0x0-0x7F",
|
||
"--name", name,
|
||
ttf],
|
||
check=True
|
||
)
|
||
print(f" ✓ fonts/{name}.pf2")
|
||
|
||
if __name__ == "__main__":
|
||
print("Building SamiOS GRUB theme assets...")
|
||
make_background()
|
||
make_icons()
|
||
make_fonts()
|
||
print("Done.")
|