77 lines
3.2 KiB
Python
77 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Compose the promotional overview from real gallery captures (requires Pillow)."""
|
|
from pathlib import Path
|
|
import subprocess
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
GALLERY = ROOT / "screenshots"
|
|
WIDTH, HEIGHT = 2400, 1800
|
|
|
|
|
|
def font(size, bold=False):
|
|
family = "DejaVu Sans:style=Bold" if bold else "DejaVu Sans"
|
|
path = subprocess.check_output(
|
|
["fc-match", family, "-f", "%{file}"], text=True
|
|
).strip()
|
|
return ImageFont.truetype(path, size)
|
|
|
|
|
|
def main():
|
|
canvas = Image.new("RGB", (WIDTH, HEIGHT))
|
|
draw = ImageDraw.Draw(canvas)
|
|
# A quiet ink/teal gradient keeps the actual application views prominent.
|
|
for y in range(HEIGHT):
|
|
t = y / HEIGHT
|
|
draw.line((0, y, WIDTH, y), fill=(int(13 + 6*t), int(24 + 4*t), int(31 + 5*t)))
|
|
white, muted, teal = "#edf5f5", "#a4b7c1", "#74dbc1"
|
|
|
|
def text(x, y, value, size, color=white, bold=False):
|
|
draw.text((x, y), value, font=font(size, bold), fill=color)
|
|
|
|
def capture(name, box, x, y, w, h):
|
|
with Image.open(GALLERY / (name + ".png")) as source:
|
|
crop = source.convert("RGB").crop(box)
|
|
# Fit without distorting UI proportions; the remaining space is the card.
|
|
scale = min(w / crop.width, h / crop.height)
|
|
crop = crop.resize(
|
|
(round(crop.width * scale), round(crop.height * scale)),
|
|
Image.Resampling.LANCZOS,
|
|
)
|
|
canvas.paste(crop, (x + (w-crop.width)//2, y + (h-crop.height)//2))
|
|
|
|
text(80, 38, "xtc", 150, teal, True)
|
|
draw.line((370, 75, 370, 207), fill="#35525a", width=2)
|
|
text(420, 63, "A lightweight, modular DAW.", 65, bold=True)
|
|
text(424, 154, "Compose. Shape your sound. Connect your ideas.", 35, muted)
|
|
text(82, 252, "ARRANGE YOUR IDEAS", 23, teal, True)
|
|
text(2320 - draw.textlength("Audio + MIDI sequencing", font=font(23)), 252,
|
|
"Audio + MIDI sequencing", 23, muted)
|
|
|
|
draw.rounded_rectangle((76, 304, 2324, 1158), radius=15, fill="#080f15", outline="#36515b", width=2)
|
|
capture("sequencer-loop", (0, 20, 1400, 540), 82, 310, 2236, 842)
|
|
|
|
cards = [
|
|
(80, "01", "Write melodies", "Piano roll + note velocities",
|
|
"piano-roll-velocity", (24, 230, 930, 804)),
|
|
(836, "02", "Build your mix", "Track / bus routing + automation",
|
|
"mixer-playing", (24, 230, 1380, 804)),
|
|
(1592, "03", "Connect your effects", "Modular track insert chains",
|
|
"track-inserts-vst3", (24, 188, 1356, 425)),
|
|
]
|
|
for x, number, title, caption, source, box in cards:
|
|
text(x, 1205, number, 23, teal, True)
|
|
text(x+48, 1196, title, 34, bold=True)
|
|
text(x, 1253, caption, 24, muted)
|
|
draw.rounded_rectangle((x, 1309, x+728, 1634), radius=12, fill="#181d23", outline="#354852", width=2)
|
|
capture(source, box, x+10, 1319, 708, 305)
|
|
|
|
draw.line((80, 1690, 2320, 1690), fill="#354852", width=2)
|
|
text(80, 1720, "LINUX FIRST / OPEN SOURCE / MIT LICENSE", 23, teal, True)
|
|
text(1580, 1720, "In development · Actual application captures", 23, muted)
|
|
canvas.save(GALLERY / "overview.png", optimize=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|