← Back to the portfolio
How it works

Class Allocations

Collect everyone's availability, let an algorithm search a million arrangements for the fairest timetable, then run the week and measure it.

One small website did three jobs: it gathered availability from 47 students, published the timetable the allocator produced, and during the week hosted a photo feed and an anonymous audience survey. A report page then turned 267 survey responses into charts.

The big picture

Students
Availability formTick and rank the classes you can make
Supabase
DatabaseRoster, timetable, picks, posts, feedback
Photo storageFeed uploads
My laptop
AllocatorSearches for the lowest-penalty timetable
Hand checksFinal tweaks, then publish
During the week
Groups pageWho presents where, by class and by person
Photo feedPosts, likes, comments
QR surveyAnonymous audience feedback
Afterwards
Report267 responses charted, saved as PDF

The website is static pages on GitHub Pages. Supabase is the shared memory behind it.

Step by step

  1. Load the roster and timetable Supabase

    A setup script put the class list and all 23 first-year class times into a Supabase database.

  2. Students pick their times Website

    Each student found their name, ticked every class they could attend (at least five) and dragged them into order of preference. A dashboard showed me who still hadn't answered.

  3. Close and export Laptop

    Once submissions closed, everyone's answers were exported to one file for the allocator.

  4. The allocator builds a first draft Laptop

    Students with the fewest options are placed first, so they aren't squeezed out by people with plenty of choice.

  5. Then it searches for something better Laptop

    The draft gets a penalty score. Big penalties go to hard rules (no one in two rooms at once, no one in a class they can't make, every class covered, no group over the cap). Smaller ones go to preferences (an experienced presenter in each group, even group sizes, people's top choices). It then tries a million small swaps, keeping the ones that lower the score. This technique is called simulated annealing. It runs six times from different random starts and keeps the best.

  6. A human checks it Laptop

    I capped groups at five and made a handful of manual fixes for special cases. The result was 102 presentation slots across 23 classes, with no clashes.

  7. Publish the groups GitHub Pages

    A script turned the result into a groups page listing who presents where, viewable by class or by person.

  8. Run the week Website

    After each class, presenters posted photos to a shared feed that others could like and comment on. Photos were stored in Supabase, and iPhone photos were converted automatically.

  9. The audience gives feedback Website

    A QR code on the screen opened a short anonymous survey: pick your class, four quick questions and two optional written answers.

  10. Turn it into a report Website

    A report page pooled all 267 responses from 21 classes into bar charts, sorted written comments into positive, constructive and critical, and mixed in feed photos. The browser's own "Save as PDF" made the final document.

The pieces

Simulated annealing

A search method that accepts some worse moves early on to escape dead ends, then settles on the best arrangement.

Far too many possible timetables to check by hand or one by one.

Penalty scoring

Every rule and preference is a weighted penalty, so the algorithm knows which to break first.

Some wishes can't all be met. This makes the trade-offs explicit.

Supabase

Database and photo storage the web pages talk to directly, with rules that stop the public changing the roster or groups.

A shared backend for a one-week project without running a server.

Node.js scripts

Setup, export, allocation and page generation all run on my laptop.

The heavy work runs once, so it doesn't need to be online.

GitHub Pages

Free hosting for the static site.

Zero cost and zero maintenance.

Browser "Save as PDF"

The report is a web page designed to print well.

No PDF library needed.

Trade-offs I chose