from [Link] import canvas from [Link].
pagesizes
import A4 from [Link] import HexColor, white #
─────────────── A4 LANDSCAPE
─────────────── W, H = A4[1], A4[0] # 841.9 x 595.3 pts
(297 x 210 mm) c =
[Link]("/home/claude/timetable_a4.pdf", pagesize=(W, H))
# ─────────────── PALETTE ───────────────
BG = HexColor("#0e1118") CARD = HexColor("#161c2e")
HDRSTRIP = HexColor("#1a2035") ACCENT =
HexColor("#6366f1") GREEN = HexColor("#34d399") ORANGE
= HexColor("#f59e0b") PURPLE = HexColor("#a78bfa") TEXT =
HexColor("#e2e5ec") DIM = HexColor("#6b7280") BORDER =
HexColor("#252d3e") LCONT = HexColor("#9ca3af") #
─────────────── DATA ───────────────
ROWS = [ ("08:00 – 09:30", [ ("Understanding of Quran-II",
"#URCG-5130", "To be allocated", "Physics Hall",
"COMBINED"), ("Database Systems", "#CMPC-5203",
"Muhammad Fahad", "MAB CR162", None), ("Object Oriented
Prog.", "#CMPC-5202", "Ms. Muzzamil Rani","MAB CR161",
None), ("Object Oriented Prog.", "#CMPC-5202", "Ms. Muzzamil
Rani","MAB CR161", None), ("Calculus & Analytical Geo.",
"#URCQ-5102", "Maryam Bashir", "MAB CR162", None), ]),
("09:30 – 11:00", [ ("↑ Quran continues…", "", "", "", "CONT"),
None, ("Database Systems", "#CMPC-5203", "Muhammad Fahad",
"MAB CR162", None), ("Database Systems", "#CMPC-5203",
"Muhammad Fahad", "MAB CR162", None), ("Expository
Writing", "#URCG-5119", "Faizan Ahmad", "MAB CR162",
None), ]), ("10:30 – 12:00", [ ("↑ Quran continues…", "", "", "",
"CONT"), ("Object Oriented Prog.", "#CMPC-5202", "Ms.
Muzzamil Rani","MAB CR161", None), None, None, None, ]),
("11:00 – 12:30", [ ("Object Oriented Prog.", "#CMPC-5202", "Ms.
Muzzamil Rani","MAB CR160", None), None, ("Database
Systems", "#CMPC-5203", "Muhammad Fahad", "MAB CR160",
"PRACTICAL"), ("Digital Logic Design", "#CMPC-5204",
"Ayesha Kausar", "MAB L-04", "LAB"), ("Mathematics-II",
"#URCM-5108", "safia Batool", "MAB CR162", None), ]), ("12:00
– 14:00", [ None, ("Digital Logic Design", "#CMPC-5204",
"Ayesha Kausar", "MAB CR161", None), None, None, None, ]),
("12:30 – 14:00", [ ("Digital Logic Design", "#CMPC-5204",
"Ayesha Kausar", "MAB L-02", "LAB"), None, ("Calculus &
Analytical Geo.", "#URCQ-5102", "Maryam Bashir", "MAB
CR161", None), None, None, ]), ] DAYS = ["MONDAY",
"TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]
CLASS_COUNTS = [3, 3, 4, 3, 3] # ───────────────
LAYOUT (fills the sheet) ─────────────── MARGIN =
20 # all sides TITLE_H = 52 # header block height NOTE_H = 38
# bottom note strip height GAP = 6 # gap title→table and
table→note TABLE_W = W - MARGIN * 2 # 801.9 TABLE_H =
H - MARGIN * 2 - TITLE_H - NOTE_H - GAP * 2 # fills
remaining TIME_COL = 64 DAY_W = (TABLE_W - TIME_COL)
/ 5 # ~147.6 each DAY_HDR_H = 27 ROW_H = (TABLE_H -
DAY_HDR_H) / len(ROWS) # ~76.7 # anchors TX = MARGIN #
table left TY = H - MARGIN - TITLE_H - GAP # table top (y of
top edge) # ─────────────── HELPERS
─────────────── def rounded_rect(c, x, y, w, h, r=5,
fill=None, stroke=None, sw=0.6): [Link]() if fill:
[Link](fill) if stroke: [Link](stroke);
[Link](sw) p = [Link]() [Link](x+r, y)
[Link](x+w-r, y) [Link](x+w-r, y, x+w, y, x+w, y+r)
[Link](x+w, y+h-r) [Link](x+w, y+h-r, x+w, y+h, x+w-r, y+h)
[Link](x+r, y+h) [Link](x+r, y+h, x, y+h, x, y+h-r) [Link](x,
y+r) [Link](x, y+r, x, y, x+r, y) [Link]() [Link](p, fill=1 if
fill else 0, stroke=1 if stroke else 0) [Link]() def
tag_badge(c, x, y, label, color): """Draw a small coloured tag.
Returns the width used.""" [Link]() tw = [Link](label,
"Helvetica-Bold", 5.8) + 12 # filled bg (semi-transparent via
drawing twice) rounded_rect(c, x, y, tw, 9, r=2, fill=color) #
overdraw with card bg at partial alpha — simulate transparency
[Link](HexColor("#161c2e")) [Link](0.78)
rounded_rect(c, x, y, tw, 9, r=2, fill=HexColor("#161c2e"))
[Link](1.0) # border rounded_rect(c, x, y, tw, 9, r=2,
stroke=color, sw=0.7) # label [Link](color)
[Link]("Helvetica-Bold", 5.8) [Link](x + 6, y + 2, label)
[Link]() return tw # ─────────────── 1.
BACKGROUND ─────────────── [Link](BG)
[Link](0, 0, W, H, fill=1) # soft glow [Link]()
[Link](ACCENT) [Link](0.055) [Link](W/2, H -
40, 240, fill=1) [Link]() # ─────────────── 2.
TITLE BLOCK ─────────────── title_y = H - MARGIN
- 22 # baseline of big title [Link](white)
[Link]("Helvetica-Bold", 19) [Link](W/2, title_y,
"BS in ARTIFICIAL INTELLIGENCE") # info badges badges =
[("Regular 1","2025-2029"), ("Semester","#2"), ("Spring","2026"),
("Student","Talha Mughal")] bw, bgap = 100, 8 total =
len(badges)*bw + (len(badges)-1)*bgap bx = W/2 - total/2 by =
title_y - 24 for lbl, val in badges: rounded_rect(c, bx, by, bw, 18,
r=7, fill=HDRSTRIP, stroke=BORDER, sw=0.5)
[Link](GREEN); [Link]("Helvetica-Bold", 7)
[Link](bx+8, by+6, lbl) lw = [Link](lbl, "Helvetica-
Bold", 7) [Link](TEXT); [Link]("Helvetica", 7)
[Link](bx+8+lw+4, by+6, val) bx += bw + bgap #
─────────────── 3. TABLE OUTER BORDER
─────────────── rounded_rect(c, TX, TY - TABLE_H,
TABLE_W, TABLE_H, r=9, stroke=BORDER, sw=1.3) #
─────────────── 4. DAY HEADERS
─────────────── # TIME header cell rounded_rect(c, TX,
TY - DAY_HDR_H, TIME_COL, DAY_HDR_H, r=9,
fill=HDRSTRIP) # clip top-right corners visually by drawing a rect
over them (square corners on inside) [Link](HDRSTRIP)
[Link](TX + 5, TY - DAY_HDR_H, TIME_COL - 5,
DAY_HDR_H, fill=1) [Link](DIM); [Link]("Helvetica-
Bold", 7) [Link](TX + TIME_COL/2, TY -
DAY_HDR_H/2 - 2, "TIME") for i, day in enumerate(DAYS): dx =
TX + TIME_COL + i * DAY_W # bg [Link](HDRSTRIP)
[Link](dx, TY - DAY_HDR_H, DAY_W, DAY_HDR_H, fill=1) #
bottom border [Link](BORDER); [Link](0.8)
[Link](dx, TY - DAY_HDR_H, dx + DAY_W, TY - DAY_HDR_H)
# vertical divider full height if i > 0: [Link](BORDER);
[Link](0.5) [Link](dx, TY, dx, TY - TABLE_H) # day name
[Link](ACCENT); [Link]("Helvetica-Bold", 9)
[Link](dx + 10, TY - 17, day) # count [Link](DIM);
[Link]("Helvetica", 6.2) [Link](dx + 10 +
[Link](day, "Helvetica-Bold", 9) + 5, TY - 16, f"
{CLASS_COUNTS[i]} classes") # TIME col right border
[Link](BORDER); [Link](0.7) [Link](TX +
TIME_COL, TY, TX + TIME_COL, TY - TABLE_H) #
─────────────── 5. ROWS ───────────────
TAG_COLORS = {"LAB": GREEN, "PRACTICAL": PURPLE,
"COMBINED": ORANGE} for row_i, (time_label, cells) in
enumerate(ROWS): row_top = TY - DAY_HDR_H - row_i *
ROW_H row_bot = row_top - ROW_H # horizontal rule
[Link](BORDER); [Link](0.45) [Link](TX,
row_bot, TX + TABLE_W, row_bot) # ── time label centred in
time column ── mid_y = row_top - ROW_H / 2 parts =
time_label.split(" – ") [Link](ACCENT);
[Link]("Helvetica-Bold", 7.5) [Link](TX +
TIME_COL/2, mid_y + 6, parts[0]) [Link](DIM);
[Link]("Helvetica", 6) [Link](TX +
TIME_COL/2, mid_y - 1, "─") [Link](ACCENT);
[Link]("Helvetica-Bold", 7.5) [Link](TX +
TIME_COL/2, mid_y - 11, parts[1]) # ── day cells ── for col_i,
cell in enumerate(cells): if cell is None: continue cx = TX +
TIME_COL + col_i * DAY_W course, code, teacher, room, tag =
cell is_cont = (tag == "CONT") PAD = 5 card_x = cx + PAD
card_y = row_bot + PAD card_w = DAY_W - PAD * 2 card_h =
ROW_H - PAD * 2 if is_cont: rounded_rect(c, card_x, card_y,
card_w, card_h, r=5, fill=HexColor("#131820"), stroke=BORDER,
sw=0.5) [Link](ORANGE) [Link](card_x, card_y, 3, card_h,
fill=1) [Link](LCONT); [Link]("Helvetica-Oblique", 7.5)
[Link](card_x + 10, card_y + card_h/2 - 3, course) continue
# normal card bar = TAG_COLORS.get(tag, ACCENT) if tag else
ACCENT rounded_rect(c, card_x, card_y, card_w, card_h, r=5,
fill=CARD, stroke=BORDER, sw=0.5) # left colour bar
[Link](bar) [Link](card_x, card_y + 4, 3, card_h - 8, fill=1) #
text stack tx = card_x + 10 ly = card_y + card_h - 13 # course name
[Link](white); [Link]("Helvetica-Bold", 7.8)
[Link](tx, ly, course) # tag badge if tag: tbx = tx +
[Link](course, "Helvetica-Bold", 7.8) + 5 tag_badge(c, tbx,
ly - 1.5, tag, TAG_COLORS.get(tag, ACCENT)) # code ly -= 11
[Link](ACCENT); [Link]("Helvetica", 6.5)
[Link](tx, ly, code) # teacher ly -= 10 [Link](DIM);
[Link]("Helvetica", 6.2) [Link](tx, ly, "Teacher: " +
teacher) # room ly -= 9.5 [Link](GREEN);
[Link]("Helvetica-Bold", 6.2) [Link](tx, ly, "Room: " +
room) # ─────────────── 6. BOTTOM NOTE BAR
─────────────── note_top = TY - TABLE_H - GAP
note_bot = note_top - NOTE_H rounded_rect(c, TX, note_bot,
TABLE_W, NOTE_H, r=6, fill=HexColor("#121820"),
stroke=BORDER, sw=0.7) # left: Note text
[Link](ORANGE); [Link]("Helvetica-Bold", 6.5)
[Link](TX + 12, note_top - 14, "Note:") [Link](DIM);
[Link]("Helvetica", 6) nw = [Link]("Note:", "Helvetica-
Bold", 6.5) [Link](TX + 12 + nw + 5, note_top - 14, "On
Wednesday, Database Systems is back-to-back " "(09:30-11:00
Theory @ CR162 + 11:00-12:30 Practical @ CR160). " "All entries
verified from the source timetable PDF.") # bottom line: student
info [Link](DIM); [Link]("Helvetica", 5.8)
[Link](TX + 12, note_bot + 8, "Student: Talha Mughal | BS
in Artificial Intelligence – Regular 1 (2025-2029) Semester #2
Spring 2026") # right side: legend legend =