{"id":603,"date":"2025-11-30T22:42:16","date_gmt":"2025-11-30T22:42:16","guid":{"rendered":"https:\/\/mityjohn.com\/?p=603"},"modified":"2025-11-30T22:42:16","modified_gmt":"2025-11-30T22:42:16","slug":"code-chaos-copilots-the-tech-magic-behind-hockey-madness","status":"publish","type":"post","link":"https:\/\/mityjohn.com\/?p=603","title":{"rendered":"Code, Chaos &amp; Copilots: The Tech Magic Behind Hockey Madness"},"content":{"rendered":"\n<p>At first glance Hockey\u00a0Madness looked like a playful festival, but behind the confetti there was an awful lot of code. Turning a multi\u2011match tournament into an interactive experience required live scorekeeping, authentication, rule management and mobile controls for coaches. <\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"980\" height=\"1024\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/startscherm-1-980x1024.png\" alt=\"\" class=\"wp-image-628\" style=\"width:524px;height:auto\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/startscherm-1-980x1024.png 980w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/startscherm-1-287x300.png 287w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/startscherm-1-768x802.png 768w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/startscherm-1.png 1077w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><\/figure>\n\n\n\n<p>Think of it as building a game engine and a broadcast studio in your browser. In this post we peek behind the curtain \u2014 spreadsheets and all \u2014 to see how the system was architected and how modern tools like Supabase and GitHub\u00a0Copilot helped us ship quickly without losing our sanity (or our sense of humour).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">From idea to architecture<\/h2>\n\n\n\n<p>The first decision was to use a <strong>Vue\u00a03<\/strong> frontend with Vite and Tailwind\u00a0CSS. Vue\u2019s composition API allowed us to organise complex state (scores, timers, boosters) into reusable functions, while Tailwind made it easy to match HC\u00a0Lokeren\u2019s colours and adapt the layout for laptops, tablets and phones. <\/p>\n\n\n\n<p>For the backend we chose <strong>Supabase<\/strong>, an open\u2011source Firebase alternative that offers Postgres storage, authentication, auto\u2011generated REST\/GraphQL APIs and <strong>real\u2011time subscriptions out of the box<\/strong>. This meant we could build a live scoreboard without managing WebSocket servers or custom authentication flows.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"920\" height=\"1024\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/match_control-920x1024.png\" alt=\"\" class=\"wp-image-620\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/match_control-920x1024.png 920w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/match_control-269x300.png 269w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/match_control-768x855.png 768w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/match_control.png 1056w\" sizes=\"auto, (max-width: 920px) 100vw, 920px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Real\u2011time scores and boosters<\/h3>\n\n\n\n<p>At the heart of the app lies a <strong>match\u2011control dashboard<\/strong> for officials. When an official adds a goal, penalty corner or card, the change is sent to Supabase via a simple <code>INSERT<\/code> or <code>UPDATE<\/code> and then propagated to all connected clients through the real\u2011time channel. Similarly, when a booster is activated, a record is created in a <code>boosters<\/code> table with its team, effect and expiration time. Subscribed clients update their UI instantly, which is how the public scoreboard displays active boosters and countdown timers. The use of Postgres triggers ensures that effects expire automatically \u2014 once a <code>boosters<\/code> row\u2019s <code>expires_at<\/code> is in the past, a cron function cleans it up and broadcasts a \u201cbooster removed\u201d event.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"656\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/scoreboard_2-1-1024x656.png\" alt=\"\" class=\"wp-image-625\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/scoreboard_2-1-1024x656.png 1024w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/scoreboard_2-1-300x192.png 300w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/scoreboard_2-1-768x492.png 768w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/scoreboard_2-1-1536x983.png 1536w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/scoreboard_2-1.png 1676w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The match controller also supports <strong>Maddies<\/strong>, which modify multiple aspects at once. A single \u201cMaddie started\u201d event notifies the crew to place extra goals or swap balls on the pitch. After the effect ends, the system resets the rules and normal play resumes. This reactive design kept our codebase cohesive: all time\u2011based effects relied on the same subscription mechanism, whether they lasted fifteen seconds or two minutes.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"915\" height=\"847\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/booster_countdown.png\" alt=\"\" class=\"wp-image-627\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/booster_countdown.png 915w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/booster_countdown-300x278.png 300w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/booster_countdown-768x711.png 768w\" sizes=\"auto, (max-width: 915px) 100vw, 915px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Draft automation and rules engine<\/h3>\n\n\n\n<p>The pre\u2011tournament <strong>draft<\/strong> was automated using a small service that keeps track of which coach goes first in each round and handles bidding. Each bid event validates the coach\u2019s credit balance, compares bids and adjusts credits accordingly. Coaches can view their remaining credits on a live dashboard while making decisions; once a bid is accepted, the player\u2019s team assignment updates for everyone to see.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Managing rules with data<\/h2>\n\n\n\n<p>Instead of hardcoding regulations, we built a <strong>rule editor<\/strong> where admins can define and reorder cards for game rules, boosters and Maddies. Each rule includes a description, a category and a position in the list. <\/p>\n\n\n\n<p>The public \u201cgame guide\u201d reads from this dataset, so when we tweak a rule, it updates everywhere instantly. We also store metadata like whether a booster has a countdown and who may activate it. This flexible approach means we can add new Maddies (like <strong>Sniper<\/strong> or <strong>Golden\u00a0Oldies<\/strong>) without redeploying the client.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"948\" height=\"1024\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/rules_control-948x1024.png\" alt=\"\" class=\"wp-image-631\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/rules_control-948x1024.png 948w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/rules_control-278x300.png 278w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/rules_control-768x830.png 768w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/rules_control.png 1053w\" sizes=\"auto, (max-width: 948px) 100vw, 948px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1018\" height=\"1024\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/gameguide-1018x1024.png\" alt=\"\" class=\"wp-image-636\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/gameguide-1018x1024.png 1018w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/gameguide-298x300.png 298w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/gameguide-150x150.png 150w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/gameguide-768x773.png 768w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/gameguide.png 1108w\" sizes=\"auto, (max-width: 1018px) 100vw, 1018px\" \/><\/figure>\n\n\n\n<p>Coding with AI: Copilot as pair programmer<\/p>\n\n\n\n<p>Writing a full tournament system from scratch could have been a slog, but <strong>GitHub\u00a0Copilot<\/strong> acted as our silent partner. Copilot uses OpenAI\u00a0Codex to <strong>suggest code and entire functions in real time<\/strong>. <\/p>\n\n\n\n<p>In practice, this meant we could stub out a Vue component and Copilot would propose the reactive variables, API calls and event handlers we needed. When building the Supabase queries, Copilot often generated the SQL and TypeScript definitions, saving us a lot of typing. Of course, we still reviewed and refined the output, but it accelerated development and freed us to focus on game design.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building tournaments like Lego<\/h3>\n\n\n\n<p>Hockey\u00a0Madness isn\u2019t a one\u2011size\u2011fits\u2011all event; some evenings call for a simple round\u2011robin, others need a group stage followed by knock\u2011out rounds. To accommodate this, we built a <strong>tournament builder<\/strong>. Each phase (poule, bracket or single match) is stored with attributes like number of groups, teams per group and advancement criteria. <\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:66.66%\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"924\" height=\"1024\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_builder-924x1024.png\" alt=\"\" class=\"wp-image-632\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_builder-924x1024.png 924w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_builder-271x300.png 271w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_builder-768x851.png 768w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_builder.png 1085w\" sizes=\"auto, (max-width: 924px) 100vw, 924px\" \/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:33.33%\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"459\" height=\"853\" src=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_creation-1.png\" alt=\"\" class=\"wp-image-634\" srcset=\"https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_creation-1.png 459w, https:\/\/mityjohn.com\/wp-content\/uploads\/2025\/11\/tournament_creation-1-161x300.png 161w\" sizes=\"auto, (max-width: 459px) 100vw, 459px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>Phases are ordered, and the bracket generator uses that sequence to create match schedules. Admins can drag and drop phases and configure them through a form.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Lessons learned<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Real\u2011time is a game\u2011changer<\/strong> \u2013 Using Supabase\u2019s subscriptions allowed us to build responsive interfaces without deep WebSocket expertise. Even coaches on mobile devices could trigger boosters and see their effects instantly.<\/li>\n\n\n\n<li><strong>State management matters<\/strong> \u2013 Keeping the app\u2019s state in sync across multiple components and devices was challenging. We used Vue\u2019s built\u2011in <code>provide\/inject<\/code> and a few helper composables to centralise timers, scores and boosters.<\/li>\n\n\n\n<li><strong>AI helps but doesn\u2019t replace us<\/strong> \u2013 GitHub\u00a0Copilot wrote a surprising amount of boilerplate code, but human oversight remained essential, especially when integrating with Supabase or handling edge cases (like simultaneous booster activations).<\/li>\n\n\n\n<li><strong>Configurable rules are powerful<\/strong> \u2013 By storing rules in the database, we could adjust the game on the fly and reuse the same app for different events. Want to run a \u201cpenalty corners count triple\u201d night? Just add a new rule card.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Final whistle<\/h2>\n\n\n\n<p>Hockey\u00a0Madness was an experiment in <strong>rapidly infusing fun and gamification into a traditional sport<\/strong> \u2014 and it worked. The combination of a well\u2011structured Vue\/Supabase stack, an AI pair programmer and a community of enthusiastic coaches and players produced a seamless experience. <\/p>\n\n\n\n<p>Instead of replacing the sport, we layered surprises and power\u2011ups on top of it. Whether you\u2019re running a friendly league or dreaming up the next big sporting spectacle, the lessons from Hockey\u00a0Madness show that with the right tools and a bit of creative chaos, adding extra fun is completely within reach.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Links<\/strong><\/p>\n\n\n\n<p>App <a href=\"https:\/\/janvanwassenhove.github.io\/sportsmadness\">https:\/\/janvanwassenhove.github.io\/sportsmadness<\/a><\/p>\n\n\n\n<p>Github Source Code <a href=\"https:\/\/github.com\/janvanwassenhove\/sportsmadness\">https:\/\/github.com\/janvanwassenhove\/sportsmadness<\/a><\/p>\n\n\n\n<figure class=\"wp-block-embed aligncenter is-type-wp-embed is-provider-mity-john wp-block-embed-mity-john\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"uRz5yHombV\"><a href=\"https:\/\/mityjohn.com\/?p=602\">Hockey Madness: Celebrating Ten Years with Chaos and Charm<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;Hockey Madness: Celebrating Ten Years with Chaos and Charm&#8221; &#8212; miTy John\" src=\"https:\/\/mityjohn.com\/?p=602&#038;embed=true#?secret=sRJ33zaZE2#?secret=uRz5yHombV\" data-secret=\"uRz5yHombV\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>At first glance Hockey\u00a0Madness looked like a playful festival, but behind the confetti there was an awful lot of code. Turning a multi\u2011match tournament into an interactive experience required live scorekeeping, authentication, rule management and mobile controls for coaches. Think of it as building a game engine and a broadcast studio in your browser. In [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":646,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,7],"tags":[20,32,28],"class_list":["post-603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","category-development","tag-generative-ai","tag-hockey","tag-vuejs"],"_links":{"self":[{"href":"https:\/\/mityjohn.com\/index.php?rest_route=\/wp\/v2\/posts\/603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mityjohn.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mityjohn.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mityjohn.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mityjohn.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=603"}],"version-history":[{"count":3,"href":"https:\/\/mityjohn.com\/index.php?rest_route=\/wp\/v2\/posts\/603\/revisions"}],"predecessor-version":[{"id":647,"href":"https:\/\/mityjohn.com\/index.php?rest_route=\/wp\/v2\/posts\/603\/revisions\/647"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mityjohn.com\/index.php?rest_route=\/wp\/v2\/media\/646"}],"wp:attachment":[{"href":"https:\/\/mityjohn.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mityjohn.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mityjohn.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}