diff --git a/Exercise 1/css/style.css b/Exercise 1/css/style.css new file mode 100644 index 00000000..e69de29b diff --git a/Exercise 1/index.html b/Exercise 1/index.html new file mode 100644 index 00000000..8cd9fffe --- /dev/null +++ b/Exercise 1/index.html @@ -0,0 +1,143 @@ + + + + + + Exercise 1 By Mohamad Dabbabo + + + + +

Exercise 1 by Mohamad Dabbabo

+

Date Submitted: 28/04/2025

+ + +
+ + + + + + + + + + + + + + + + + + + + + + +
Some facts about me:
First NameLast NameFavorite MovieFavorite SongFavorite Video
MohamadDabbabo + +

Ghost in the Shell (1995)
Cyberpunk, AI, Philosophy, Identity

+ + Ghost in the Shell poster + +
+

Click “Play” to hear this concert performance
held in memory of the 2011 victims.

+ +
+ +
+ + +
+ + +

Enter your details below:

+ +
+ + +

+ + + +

+ + + +

+ + +
+ Available Days: +
+
+
+
+
+
+ +
+
+ + + +

+ + +
+ Working on a new website? +
+ +
+
+ + + +

+ + + + +
+ + + diff --git a/Exercise 1/js/script.js b/Exercise 1/js/script.js new file mode 100644 index 00000000..e69de29b diff --git a/Exercise 1/media/Kenji_Kawai_Making_of_a_Cyborg.mp3 b/Exercise 1/media/Kenji_Kawai_Making_of_a_Cyborg.mp3 new file mode 100644 index 00000000..f38739f7 Binary files /dev/null and b/Exercise 1/media/Kenji_Kawai_Making_of_a_Cyborg.mp3 differ diff --git a/Exercise 2/css/style.css b/Exercise 2/css/style.css new file mode 100644 index 00000000..cf7bfd8e --- /dev/null +++ b/Exercise 2/css/style.css @@ -0,0 +1,127 @@ +/* palette variables (for later) */ +:root{ + --primary:#0077b6; /* deep blue */ + --accent:#00b4d8; /* cyan */ + --light:#f0f8ff; /* very light blue */ + --bg:#e8f4ff; /* page background */ + --border:#185b8c; /* darker blue */ + --table-head:#e63946;/* red */ + } + + /* base */ + body{ + margin:0; + font-family:Arial, Helvetica, sans-serif; /* Fonts I picked that resonate with me */ + background:var(--bg); + color:#222; + padding:0 12px 40px; + } + + /* reusable soft-card */ + .soft{ + background:#fff; + border:2px solid var(--border); + padding:20px; + margin:24px auto; + max-width:940px; + box-shadow:0 0 12px #0077b620; /* subtle bloom */ + } + + /* headings */ + h1{ + color:#fff; + background:var(--primary); + text-align:center; + margin:0 -12px 24px; + padding:28px 12px; + text-shadow:0 0 6px #ffffffaa; /* glowing effect */ + } + h2{ + color:var(--primary); + border-bottom:4px solid var(--accent); + padding-bottom:4px; + margin:28px auto 12px; + max-width:940px; + text-shadow:0 0 4px #00b4d880; + } + h3{ + margin:6px 0 24px; + color:var(--accent); + text-align:center; + text-shadow:0 0 4px #00b4d880; + } + + /* description paragraph */ + p:first-of-type{ + max-width:760px; + margin:0 auto 24px; + } + + /* table */ + table { + border-collapse: collapse; + width: 50%; + margin-left: auto; + margin-right: auto; + text-align: center; + } + + th,td{ + border:1px solid var(--accent); + padding:10px 6px; + text-align:center; + } + th{ + background:var(--table-head); + color:#fff; + } + + /* media thumbs */ + img{ + border:4px solid var(--accent); + padding:4px; + background:#fff; + box-shadow:0 0 8px #00b4d820; + } + + /* form */ + form{ + background:#fff; + border:2px solid var(--border); + padding:20px; + max-width:540px; + margin:24px auto; + box-shadow:0 0 10px #0077b620; + } + label{display:block;margin:10px 0;} + input,select,textarea{ + width:100%;max-width:100%; + padding:6px;border:1px solid #ccc;margin-top:4px; + } + fieldset{ + border:1px solid var(--accent); + padding:10px;margin:14px 0; + } + + /* Button CSS, background uses primary variable, no border, changes cursor to pointer */ + button{ + background:var(--primary); + color:#fff; + border:none; + padding:8px 18px; + margin-top:12px; + cursor:pointer; + } + /* This makes the reset button have a unique */ + button[type="reset"]{background:var(--accent);} + + /* This uses :hover to change colors */ + button:hover{ + background:var(--light); + color:#000000; + box-shadow:0 0 6px #00b4d8aa; + } + + /* figures */ + figure{margin:24px auto;max-width:320px;text-align:center;} + figcaption{margin-bottom:6px;font-weight:bold;} \ No newline at end of file diff --git a/Exercise 2/index.html b/Exercise 2/index.html new file mode 100644 index 00000000..5d2943ab --- /dev/null +++ b/Exercise 2/index.html @@ -0,0 +1,114 @@ + + + + + + Robotics & AI Expo 2025 – Information Page + + + + + + + + +

Robotics & AI Expo 2025

+

Saturday · 24 May 2025 · Gesamtschule Konradsdorf · 10:00–17:00

+ + +

+ Ever wanted to unleash your AI skills? Join us for a day of hands-on workshops (practical), thrilling competitions (hackathons), and thought-provoking debates (About future AI)! + You will learn about the latest in robotics and AI, and have the chance to showcase your own projects. Even bring your arguments to the table! + So what are you waiting for? Come join the event! +

+ + +

Event Schedule

+ + + + + + + + + + + + + + + +
TimeActivityLocation
10 : 00Opening KeynoteAula
11 : 00Autonomous-Bot RaceSporthalle
13 : 00ML Workshop: "Teach a CNN to lower grade students"Lab 1B
15 : 30Debate – "Will AI surpass us?"Auditorium
16 : 45Awards & ClosingAula
+ + +

Sneak-peek

+

+ + Expo poster by GPT-4o image gen + +

+ + + + +
+
10-seconds highlight reel:
+ +
+ + + +

Register / Contact Us

+
+ + + + + + + + + +
+ Interested in: + + + +
+ + + + + +
+ + + + + diff --git a/Exercise 2/media/matplotlib_animation.ipynb b/Exercise 2/media/matplotlib_animation.ipynb new file mode 100644 index 00000000..fa6f9f50 --- /dev/null +++ b/Exercise 2/media/matplotlib_animation.ipynb @@ -0,0 +1,208 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 10, + "id": "0930f850", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABOwAAAEcCAYAAAB07ys7AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABTS0lEQVR4nO3dd3gU1eLG8Xc32Wx6AVIpCYQO0qULSBGUqmABlWJHVBDsWOCKqBfxYgOx4k9BVATEBoKAFOlKL6FDgCQkIb1n5/fHyoa9CRAUzVz9fp5nH8jMmZkzs7uzu++cc8ZiGIYhAAAAAAAAAKZgregKAAAAAAAAAChBYAcAAAAAAACYCIEdAAAAAAAAYCIEdgAAAAAAAICJENgBAAAAAAAAJkJgBwAAAAAAAJgIgR0AAAAAAABgIgR2AAAAAAAAgIkQ2AEAAAAAAAAmQmAHAMDfyIQJE2SxWJScnPynb2vlypWyWCxauXLln74twKyOHDkii8WiV1555U/f1qxZs2SxWHTkyJFLXpb3KwAA/1sI7AAAqCBnf3yffXh6eqpq1aoaPny4Tpw4UdHVc5k+fbpmzZpV0dVw+eijj9S4cWP5+vqqevXqGjp0qE6ePPm71jV9+nRZLBa1adPmvGUsFoseeOCBi64rJibG7fk899GrV6/fVb8/m8Ph0KxZs9SvXz9Vr15dfn5+aty4sSZNmqS8vLwyl3n//ffVoEEDeXt7q06dOnrjjTdKlZk/f75uvvlm1apVS76+vqpXr57GjRuntLS0UmXPd9zuu+++y727br7++mt17txZYWFh8vX1Va1atXTTTTdp8eLFf+p2AQAAysOzoisAAMA/3b/+9S/VrFlTeXl5Wr9+vWbNmqU1a9Zo586d8vb2rujqafr06apSpYqGDx/uNr1Tp07Kzc2Vl5fXX1aXBQsWaPjw4ercubMeeOABJSUlad68eYqLi1NUVNQlr2/27NmKiYnRxo0bdeDAAdWuXfsP1a9Zs2YaN25cqem/p25/hZycHI0YMUJt27bVfffdp7CwMK1bt07PPfecfvzxRy1fvlwWi8VVfubMmbrvvvs0cOBAjR07VqtXr9ZDDz2knJwcPf74465y99xzj6KionTbbbepRo0a2rFjh95880199913+uWXX+Tj4+NWj7KOW926df+0/X7llVf06KOPqnPnznryySfl6+urAwcOaNmyZZo7d65pA1YAAPDPQWAHAEAFu/baa9WqVStJ0l133aUqVaro5Zdf1qJFi3TTTTdVcO3Oz2q1/uWB4ty5c1WpUiUtXrzYte1nn31WBQUFl7yuw4cP6+eff9b8+fN17733avbs2Xruuef+UP2qVq2q22677Q+t46/k5eWltWvXqn379q5pd999t2JiYlyhXffu3SVJubm5Gj9+vHr37q158+a5yjocDj3//PO65557FBISIkmaN2+eunTp4ratli1batiwYZo9e7buuusut3l/5XErKirS888/rx49euiHH34oNT8pKekvqQcAAMCF0CUWAACTueqqqyRJBw8edJu+fPlyXXXVVfLz81NwcLD69++vPXv2lLmO5ORk3XTTTQoMDFTlypU1evToUl0czwYXsbGxstvtiomJ0VNPPaX8/HxXmZiYGO3atUs//fSTq6vi2SDmfGNibdiwQdddd51CQkLk5+enJk2a6LXXXnPNT0hI0IgRI1StWjXZ7XZFRkaqf//+5RqXy2q1qqioSB4eHm7Tf08rv9mzZyskJES9e/fWoEGDNHv27Etex6VKSkpSaGiounTpIsMwXNMPHDggPz8/3Xzzza5pXbp0UePGjbVlyxa1b99ePj4+qlmzpt5+++0y13vnnXcqPDxc3t7eatq0qT766KOL1sfLy8strDvr+uuvlyS319eKFSuUkpKi+++/363sqFGjlJ2drW+//dat7uVZ57kKCgqUnZ190Tr/UcnJycrIyFCHDh3KnB8WFub2d15eniZMmKC6devK29tbkZGRuuGGG0q9PyXpnXfecb2frrzySm3atKlUmb1792rQoEGqVKmSvL291apVKy1atKhUuV27dqlr167y8fFRtWrVNGnSJDkcjlLlLBaLJkyYUGp6TExMqVaxZdmwYYN69eqloKAg+fr6qnPnzlq7du1FlwMAAH8uAjsAAEzmbHB1trWSJC1btkw9e/ZUUlKSJkyYoLFjx+rnn39Whw4dygy6brrpJuXl5enFF1/Uddddp9dff1333HOPW5m77rpLzz77rFq0aKH//Oc/6ty5s1588UXdcsstrjLTpk1TtWrVVL9+fX388cf6+OOPNX78+PPWfenSperUqZN2796t0aNHa+rUqbr66qv1zTffuMoMHDhQCxYs0IgRIzR9+nQ99NBDyszM1LFjxy56bEaMGKGMjAw9++yzFy17MbNnz9YNN9wgLy8vDR48WPv37y8zYLkUhYWFSk5OLvXIzc2V5AyDZsyYoZ9++sk19pvD4dDw4cMVEBCg6dOnu63vzJkzuu6669SyZUv9+9//VrVq1TRy5Eh98MEHrjK5ubnq0qWLPv74Y916662aMmWKgoKCNHz4cLeg9FIkJCRIkqpUqeKa9uuvv0qSqzXoWS1btpTVanXNv5R1nrV8+XL5+vrK399fMTExv7ve5REWFiYfHx99/fXXSk1NvWDZ4uJi9enTRxMnTlTLli01depUjR49Wunp6dq5c6db2Tlz5mjKlCm69957NWnSJB05ckQ33HCDCgsLXWV27dqltm3bas+ePXriiSc0depU+fn5acCAAVqwYIGrXEJCgq6++mpt3bpVTzzxhMaMGaP/+7//u+zHZfny5erUqZMyMjL03HPPafLkyUpLS1PXrl21cePGy7otAABwiQwAAFAhPvzwQ0OSsWzZMuP06dPG8ePHjXnz5hmhoaGG3W43jh8/7irbrFkzIywszEhJSXFN27Ztm2G1Wo2hQ4e6pj333HOGJKNfv35u27r//vsNSca2bdsMwzCMrVu3GpKMu+66y63cI488Ykgyli9f7prWqFEjo3PnzqXqv2LFCkOSsWLFCsMwDKOoqMioWbOmER0dbZw5c8atrMPhMAzDMM6cOWNIMqZMmVL+A3WO6dOnG3a73ZBkvPbaa79rHYZhGJs3bzYkGUuXLnXVr1q1asbo0aNLlZVkjBo16qLrjI6ONiSV+XjxxRfdyg4ePNjw9fU14uLijClTphiSjIULF7qV6dy5syHJmDp1qmtafn6+67VQUFBgGIZhTJs2zZBkfPLJJ65yBQUFRrt27Qx/f38jIyOj3MflrO7duxuBgYFuz+OoUaMMDw+PMsuHhoYat9xyywXXeeeddxoeHh5GXFyc2/S+ffsaL7/8srFw4ULj/fffN6666ipDkvHYY49dcr3L69lnnzUkGX5+fsa1115rvPDCC8aWLVtKlfvggw8MScarr75aat7Z1/Thw4cNSUblypWN1NRU1/yvvvrKkGR8/fXXrmndunUzrrjiCiMvL89tPe3btzfq1KnjmjZmzBhDkrFhwwbXtKSkJCMoKMiQZBw+fNg1XZLx3HPPlapfdHS0MWzYMNff//1+dTgcRp06dYyePXu69sUwDCMnJ8eoWbOm0aNHjzKOHAAA+KvQwg4AgArWvXt3hYaGqnr16ho0aJD8/Py0aNEiVatWTZJ06tQpbd26VcOHD1elSpVcyzVp0kQ9evTQd999V2qdo0aNcvv7wQcflCRX2bP/jh071q3c2YH/z+3eWF6//vqrDh8+rDFjxig4ONht3tkbF/j4+MjLy0srV67UmTNnLmn9X331lUaNGqV58+Zp/PjxGjNmjD788EO3MvXq1dPtt99+0XXNnj1b4eHhuvrqq131u/nmmzV37lwVFxdfUr3O1aZNGy1durTUY/DgwW7l3nzzTQUFBWnQoEF65plndPvtt6t///6l1ufp6al7773X9beXl5fuvfdeJSUlacuWLZKcz2VERITbNmw2mx566CFlZWXpp59+uqR9mDx5spYtW6aXXnrJ7Xm80A1GvL29Xa0IyzJnzhy9//77GjdunOrUqeM2b9GiRXrsscfUv39/3XHHHfrpp5/Us2dPvfrqq4qPj7+kupfXxIkTNWfOHDVv3lxLlizR+PHj1bJlS7Vo0cKty+6XX36pKlWquN4/5zr3ZhySdPPNN7u1ij3btf3QoUOSpNTUVC1fvlw33XSTMjMzXa0vU1JS1LNnT+3fv991d+jvvvtObdu2VevWrV3rCw0N1a233nrZjsHWrVu1f/9+DRkyRCkpKa76ZGdnq1u3blq1alWZXXABAMBfg5tOAABQwd566y3VrVtX6enp+uCDD7Rq1SrZ7XbX/KNHj0pyhlH/rUGDBlqyZImys7Pl5+fnmv7foUhsbKysVqur++zRo0dltVpL3RU1IiJCwcHBrm1eirNjejVu3Pi8Zex2u15++WWNGzdO4eHhatu2rfr06aOhQ4cqIiLigut//PHHde2116pPnz7q06ePEhMTdffddysgIECDBg1STk6ODh8+XGa4cq7i4mLNnTtXV199tQ4fPuya3qZNG02dOlU//vijrrnmmkvY8xJVqlRx3aThQipVqqTXX39dN954o8LDw/X666+XWS4qKsrteZVK7p565MgRtW3bVkePHlWdOnVktbpfh23QoIEkXdJz+dlnn+npp5/WnXfeqZEjR7rN8/HxOe/NPfLy8krd+fWs1atX684771TPnj31wgsvXLQOFotFDz/8sJYsWaKVK1ee92YUxcXFOn36dJnzfHx8FBQUdMHtDB48WIMHD1ZGRoY2bNigWbNmac6cOerbt6/rDs0HDx5UvXr15Ol58a/MNWrUcPv7bHh3Npg+cOCADMPQM888o2eeeabMdSQlJalq1ao6evSo2rRpU2p+WeeA32v//v2SpGHDhp23THp6ulsICQAA/joEdgAAVLDWrVu7xgUbMGCAOnbsqCFDhmjfvn3y9/e/LNv479ZAF5v+ZxozZoz69u2rhQsXasmSJXrmmWf04osvavny5WrevHmZy6Smpmrfvn1uLYzefvttnT59WkOGDJGfn58OHTokq9WqQYMGXXD7y5cv16lTpzR37lzNnTu31PzZs2f/7sDuUixZskSSM9CJj48v1Srxr7Z06VINHTpUvXv3LvPGFpGRkSouLlZSUpLbjRkKCgqUkpKiqKioUsts27ZN/fr1U+PGjTVv3rxyBV+SVL16dUm64Bhzx48fV82aNcucN2zYMM2aNatc2woMDFSPHj3Uo0cP2Ww2ffTRR9qwYYM6d+5cruXP+u8boZxl/HZzkbOt1R555BH17NmzzLL/HaD/ERdrKXq2PlOmTFGzZs3KLHO5zj8AAODSEdgBAGAiHh4eevHFF3X11VfrzTff1BNPPKHo6GhJ0r59+0qV37t3r6pUqVKqFdb+/fvdwowDBw7I4XAoJiZGkhQdHS2Hw6H9+/e7WmJJUmJiotLS0lzblMof6sXGxkqSdu7cedFWZrGxsRo3bpzGjRun/fv3q1mzZpo6dao++eSTMsufrcPx48dd0zw8PDR37lxdc801GjhwoAIDAzVy5MiLttSbPXu2wsLC9NZbb5WaN3/+fC1YsEBvv/32eVuMXQ6LFy/We++9p8cee0yzZ8/WsGHDtGHDhlKB1smTJ0u1noyLi5Mkt+dy+/btcjgcbq3s9u7d65p/MRs2bND111+vVq1a6fPPPy8zWDsb6mzevFnXXXeda/rmzZvlcDhKhT4HDx5Ur169FBYWpu++++6Swp+z3UhDQ0PPWyYiIkJLly4tc15Z4WF5tGrVSh999JFOnTolyfk63bBhgwoLC2Wz2X7XOs+qVauWJGd35Yu9P6Kjo10t4M5V1jkgJCREaWlpbtMKCgpc+3A+Z9+vgYGB5WoVCgAA/lqMYQcAgMl06dJFrVu31rRp05SXl6fIyEg1a9ZMH330kdsP8507d+qHH35wC0/O+u8w6uwdSa+99lpJci0zbdo0t3KvvvqqJKl3796uaX5+fqUCgbK0aNFCNWvW1LRp00qVP9vKKCcnR3l5eW7zYmNjFRAQoPz8/POuOyQkRC1atNCcOXNcQZTkHDvt448/lsPhUGJiogYMGHDBOubm5mr+/Pnq06ePBg0aVOrxwAMPKDMzU4sWLbro/v5eaWlpuuuuu9S6dWtNnjxZ7733nn755RdNnjy5VNmioiLNnDnT9XdBQYFmzpyp0NBQtWzZUpLzuUxISNBnn33mttwbb7whf3//i7YU27Nnj3r37q2YmBh988035w0qu3btqkqVKmnGjBlu02fMmCFfX1+310xCQoKuueYaWa1WLVmy5LzBW2pqaqmWYIWFhXrppZfk5eXlGmOwLN7e3urevXuZj4YNG553uZycHK1bt67Med9//72kkq6nAwcOVHJyst58881SZc++pssrLCxMXbp00cyZM8sM087t3nvddddp/fr1bndqPX36tGbPnl1qudjYWK1atcpt2jvvvHPRFnYtW7ZUbGysXnnlFWVlZV2wPgAA4K9HCzsAAEzo0Ucf1Y033qhZs2bpvvvu05QpU3TttdeqXbt2uvPOO5Wbm6s33nhDQUFBmjBhQqnlDx8+rH79+qlXr15at26dPvnkEw0ZMkRNmzaVJDVt2lTDhg3TO++8o7S0NHXu3FkbN27URx99pAEDBrgFJS1bttSMGTM0adIk1a5dW2FhYeratWupbVqtVs2YMUN9+/ZVs2bNNGLECEVGRmrv3r3atWuXlixZori4OHXr1k033XSTGjZsKE9PTy1YsECJiYm65ZZbLnhM3njjDXXv3l2tW7fWvffeq/r16+vIkSP64IMPFB4eLqvVqiFDhmjDhg2uG3b8t0WLFikzM1P9+vUrc37btm0VGhqq2bNn6+abb75gfcpy4sSJMlsJ+vv7u8LE0aNHKyUlRcuWLZOHh4d69eqlu+66S5MmTVL//v1dz5HkbCn28ssv68iRI6pbt64+++wzbd26Ve+8846rxdc999yjmTNnavjw4dqyZYtiYmI0b948rV27VtOmTVNAQMB565uZmamePXvqzJkzevTRR0vdbCQ2Nlbt2rWT5BwX7vnnn9eoUaN04403qmfPnlq9erU++eQTvfDCC243ROnVq5cOHTqkxx57TGvWrNGaNWtc88LDw9WjRw9Jzudj0qRJGjRokGrWrKnU1FTN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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# This code was designed for the animation, since I didn't want to spend too much time doing it in Blender, I decided a quick Matplotlib would do it.\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.animation as anim\n", + "from matplotlib.patches import Rectangle\n", + "from IPython.display import HTML\n", + "import numpy as np\n", + "from matplotlib.animation import FFMpegWriter\n", + "import matplotlib as mpl\n", + "import os\n", + "import imageio_ffmpeg\n", + "\n", + "# --- DATA ---\n", + "events = [\n", + " (\"Opening Keynote\", 10.00, 11.00),\n", + " (\"Autonomous-Bot Race\", 11.00, 13.00),\n", + " (\"ML Workshop – “Teach a CNN”\", 13.00, 15.50),\n", + " (\"Debate – “Will AI surpass us?”\",15.50, 16.75),\n", + " (\"Awards & Closing\", 16.75, 17.00),\n", + "]\n", + "\n", + "# make sure the folder exists\n", + "out_dir = r'C:\\Users\\iHunter\\OneDrive\\Desktop\\Building-U\\bu-learning\\Exercise 2\\media'\n", + "os.makedirs(out_dir, exist_ok=True)\n", + "out_path = os.path.join(out_dir, 'robotics_schedule.mp4')\n", + "\n", + "# --- FIGURE SETUP ---\n", + "fig, ax = plt.subplots(figsize=(16, 2.8))\n", + "mpl.rcParams['animation.ffmpeg_path'] = imageio_ffmpeg.get_ffmpeg_exe()\n", + "\n", + "# hide everything (axes, ticks, spines)\n", + "ax.axis('off')\n", + "\n", + "\n", + "# Let's assume 1 hour between each event\n", + "margin = 1.0\n", + "ax.set_xlim(9.8, events[-1][2] + margin)\n", + "ax.set_ylim(-0.05, 0.75)\n", + "\n", + "# horizontal baseline\n", + "ax.hlines(0.05, events[0][1], events[-1][2] + margin, lw=1.5, color=\"k\")\n", + "\n", + "ax.set_title(\"Robotics & AI Expo 2025 – Schedule\", pad=25)\n", + "\n", + "# color palette + contrast helper\n", + "palette = plt.get_cmap(\"tab10\").colors\n", + "\n", + "\n", + "def best_text_colour(rgb):\n", + " r, g, b = rgb\n", + " return \"black\" if 0.2126*r + 0.7152*g + 0.0722*b > 0.55 else \"white\"\n", + "\n", + "# Set minimum bar width (for display purposes)\n", + "MIN_BAR_WIDTH = 0.9\n", + "\n", + "bars, labels, grads = [], [], [None]*len(events)\n", + "\n", + "# initial patch + text creation (width=0 to animate in)\n", + "for i, (lab, start, end) in enumerate(events):\n", + " real_w = end - start\n", + " disp_w = max(real_w, MIN_BAR_WIDTH) # enforce minimum for display\n", + " color = palette[i % len(palette)]\n", + " y0, h = 0.20, 0.40\n", + "\n", + " # bar (starts at zero, grows to disp_w)\n", + " rect = Rectangle((start, y0), 0, h, color=color, ec=\"none\", zorder=1)\n", + " ax.add_patch(rect)\n", + " bars.append((rect, real_w, disp_w))\n", + "\n", + " # label (alpha=0 at start)\n", + " txt = ax.text(start, y0 + h/2, lab,\n", + " ha=\"left\", va=\"center\",\n", + " fontsize=9, alpha=0.0,\n", + " color=best_text_colour(color),\n", + " zorder=2)\n", + " labels.append(txt)\n", + "\n", + "# gradient helper function\n", + "def make_gradient(ax, x0, w, col, y0=0.20, h=0.40, n=120):\n", + " try:\n", + " grad = np.linspace(0,1,n)[:,None] * np.array(col)\n", + " im = ax.imshow(grad[None,:,:],\n", + " extent=[x0, x0+w, y0, y0+h],\n", + " aspect=\"auto\", zorder=0.5)\n", + " im.set_clip_path(Rectangle((x0, y0), w, h, transform=ax.transData))\n", + " return im\n", + " except:\n", + " return None\n", + "\n", + "# --- ANIMATION LOGIC ---\n", + "fps = 25\n", + "frames_per_event = 40\n", + "pause_frames = 10\n", + "total_frames = len(events) * (frames_per_event + pause_frames)\n", + "\n", + "def animate(frame):\n", + " idx, local = divmod(frame, frames_per_event + pause_frames)\n", + " artists = []\n", + "\n", + " for i, ((rect, real_w, disp_w), txt) in enumerate(zip(bars, labels)):\n", + " s = events[i][1]\n", + " # Past events → full width\n", + " if i < idx:\n", + " rect.set_x(s)\n", + " rect.set_width(disp_w)\n", + " rect.set_edgecolor(\"k\")\n", + " txt.set_alpha(1.0)\n", + "\n", + " # Current event sliding in\n", + " elif i == idx and local < frames_per_event:\n", + " p = local / frames_per_event\n", + " rect.set_x(s)\n", + " rect.set_width(disp_w * p)\n", + " # if the _real_ bar is tall enough, fade in text; otherwise show full alpha\n", + " if real_w >= MIN_BAR_WIDTH:\n", + " txt.set_alpha(p)\n", + " else:\n", + " txt.set_alpha(1.0)\n", + "\n", + " # Landed/current-pause (blink outline)\n", + " elif i == idx:\n", + " rect.set_x(s)\n", + " rect.set_width(disp_w)\n", + " rect.set_edgecolor(\"k\" if (local - frames_per_event) % 2 else \"none\")\n", + " txt.set_alpha(1.0)\n", + "\n", + " # Future events → hidden\n", + " else:\n", + " rect.set_width(0)\n", + " txt.set_alpha(0.0)\n", + "\n", + " # label placement (center if wide, outside if skinny)\n", + " if disp_w >= MIN_BAR_WIDTH:\n", + " txt.set_x(s + disp_w/2)\n", + " txt.set_ha(\"center\")\n", + " else:\n", + " txt.set_x(s + disp_w + 0.05)\n", + " txt.set_ha(\"left\")\n", + "\n", + " artists += [rect, txt]\n", + "\n", + " return artists\n", + "\n", + "ani = anim.FuncAnimation(fig, animate,\n", + " frames=total_frames,\n", + " interval=1000/fps,\n", + " blit=True)\n", + "\n", + "# Display in Jupyter/VS Code interactive window\n", + "HTML(ani.to_jshtml())\n", + "# save to media/ folder (make sure it exists!)\n", + "\n", + "# --- ANIMATION SAVE ---\n", + "# set up the writer\n", + "writer = FFMpegWriter(\n", + " fps=fps,\n", + " codec='libx264',\n", + " bitrate=1800,\n", + " extra_args=['-pix_fmt', 'yuv420p']\n", + ")\n", + "\n", + "# save the file\n", + "ani.save(out_path, writer=writer)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Exercise 2/media/poster.png b/Exercise 2/media/poster.png new file mode 100644 index 00000000..d47417bd Binary files /dev/null and b/Exercise 2/media/poster.png differ diff --git a/Exercise 2/media/robotics_schedule.mp4 b/Exercise 2/media/robotics_schedule.mp4 new file mode 100644 index 00000000..57dd3454 Binary files /dev/null and b/Exercise 2/media/robotics_schedule.mp4 differ