PROLOOK SportsALL IN Tournament

ALL IN Tournament

Redesigning a live tournament site and building its 2027 registration, without disrupting the app behind it

Role
Frontend Web Developer, Marketing Side
Company
PROLOOK Sports
Timeline
2026
Team
Marketing, Design, Engineering, and QA
Stack
SvelteKit, Svelte, Tailwind CSS, Node, JavaScript

In short

  • The Register button on the live site led to a page that still said “2025 Registration is full.” There was no way for a team to register.
  • I built a full registration form for 2027, saved to the database rather than only emailed, with a staff board and three emails that did not exist before.
  • I rebuilt the rules, brackets, navigation, homepage, and footer of a live SvelteKit app owned by an engineering team in the Philippines.
  • Every change shipped through DEV, staging, QA, and production, without getting in the way of the tournament systems the engineering team already owned.

The situation

ALL IN is a youth baseball tournament run by PROLOOK, with profits going to the Autism Council of Utah.

The site was originally built in 2022 on an early version of SvelteKit and was still locked to an older version of Node. The app itself was owned by an engineering team in the Philippines, and upgrading the framework or dependencies was not something I could casually touch without risking other parts of the system.

Marketing needed a full redesign before the next tournament.

The homepage was still showing last year’s dates, the navigation needed to be rebuilt, and the overall site needed to feel much more current.

The people using the site are also not sitting at a desk.

A parent might be standing at the ballfield checking the bracket to see where their kid plays next. A coach might be pulling up the tiebreaker rules on their phone. A team manager might be trying to order gear between games.

If one of those paths breaks, the problem is immediate.

At a glance

  • 4 production releases

    Included my work

    Changes were released in smaller pieces instead of waiting for one large launch.

  • 3 emails

    That did not exist before

    A receipt to the coach, a notice to the tournament, and the acceptance email.

  • 3.5 MB → 1.8 MB

    Homepage image weight

    Without a visible change in quality.

Old pages, new pages

Scroll to move down each page. Both home pages were rebuilt from the real code at that point in git history, run as a production build at the same screen size: 2.0.94, before any of my work, and 2.0.102. Both use today’s database, so only the code differs, and the hero is a video, so both show a still frame.

For the rules and registration, the before shots come from the live site and the after shots from staging, taken the same day so the comparison is honest.

Page 1 of 6

The home page at 2.0.94

  1. 2.0.94, before any of my work.

  2. The homepage was still showing last year's dates.

  3. Rules, Teams, Brackets and Shop, as a row of icons.

  4. Custom Uniforms, at the bottom of the page above the footer.

The whole home page at version 2.0.94 — a white header with partner logos, the April 30 to May 2 dates, the Tournament Tools icon row with Shop, the Custom Uniforms block, and the footer.

Page 2 of 6

The home page at 2.0.102

  1. The navigation got the new ALL IN logo.

  2. The dropdown stays open while you move to it.

  3. 2027 DATES, Coming Soon to Utah County.

  4. The icon row was replaced with four photo tiles.

  5. Now the titles stay sharp, can scale with the layout, and can also be read by screen readers.

  6. The ProLook and Dick's section at the bottom was replaced with the staggered photo strip, white above and grey below so it runs into the footer.

  7. The WE ARE ALL IN wordmark was being stretched beyond the resolution of the original image on large screens, so I replaced it with a higher-resolution version.

The whole home page at version 2.0.102 — the black navigation with the new logo, the 2027 dates, four photo tiles for Rules, Teams, Brackets and Sponsors, the staggered photo strip, and the footer with the WE ARE ALL IN wordmark.

Page 3 of 6

The rules page, before

  1. The sections squeezed into a red bar across a photo.

  2. Every rule, white on red, from the top of the page to the bottom. Hard to read, especially on a phone, and it looked dated.

The old rules page, white text on a solid red background.

Page 4 of 6

The rules page, after

  1. The sections sit in a bar that stays with you as you scroll.

  2. White page, black text, bigger headline.

  3. Red is now an accent, not the background.

  4. The rules themselves read like a printed rule book, numbered down the margin with a line between each one.

The rebuilt rules page, black header and white page with the rules numbered down the margin.

Page 5 of 6

Registration, before

  1. What the Register button led to. Wrong year, no way forward.

A page reading "2025 Registration is full".

Page 6 of 6

Registration, after

  1. Every question the tournament asks, all required.

  2. Spots change with the division (12 for 8U and 14U, 32 for 9U to 13U).

  3. Every team wears PROLOOK uniform tops in every game.

  4. The list of agreements, each one ticked before the form will send.

  5. The form unlocks itself on the test sites and stays shut on the live site until the date.

The 2027 registration form, with the team, coach and contact questions and the list of agreements.
A Studio Display XDR seen from below, showing the rebuilt rules page with the General Rules tab open.
The rules page, on a Studio Display.

The rules on a phone

The phone version is where the red background hurt most.

After: white page, black text, bigger headline, and the sections sit in a bar that stays with you as you scroll.

Every button and section is the same as before, and so is the wording, apart from the rules that were updated.

  • The old rules page on a phone, white text on a solid red background.

    Before.

  • The rebuilt rules page on a phone, black header and white page.

    After.

The brackets page

The old brackets page with grey division buttons.

Before · Step 1 of 2

Grey blocks for the divisions

Grey blocks for the divisions that looked like unfinished placeholders.

The rebuilt brackets page, with the division buttons as outlined cards and the selected one filled red.

After · Step 2 of 2

The same picker, as outlined cards

The same division picker, now outlined cards that lift when you hover, fill red when selected, and grey out when a division has no bracket yet.

Same picker, same search, same behavior.

Step 1 of 2

Every detail

Smaller fixes, each one rebuilt from the real code at that point in git history, before and after.

  • The home page banner at 2.0.94, reading April 30 to May 2, with the opening night details.

    The banner at 2.0.94, still showing last year's dates

  • The home page banner at 2.0.102, reading 2027 Dates, Coming Soon to Utah County.

    The banner at 2.0.102

  • The Tournament Info dropdown at 2.0.99, with a Tournament Info label row above the links.

    The dropdown at 2.0.99, with its label row

  • The Tournament Info dropdown at 2.0.102, the links straight under the bar in lighter type.

    Label row removed, lighter type

  • Before — the dropdown has closed while the pointer passes over Shop on its way to the links.

    Before, the menu closed on the way to the links

  • After — the dropdown stays open with the pointer on Rules.

    Now it stays open while you move to it

  • The bottom of the rules page at 2.0.94, with the Custom Uniforms block above the footer.

    The Custom Uniforms block on every page

  • The bottom of the rules page at 2.0.102, straight from the last rule to the footer.

    Removed, and replaced on the home page by the photo strip

Key decisions

  1. Work inside the old stack instead of turning the redesign into an upgrade project

    My first instinct was to look at upgrading it.

    That would have been the wrong project.

    The engineering team already deploys and maintains the application, and changing framework versions or dependencies would have affected parts of the system I did not own.

    Instead, I pinned the exact Node version with Volta so this project always runs in the environment it expects without affecting anything else on my machine.

    That let me focus on the redesign instead of creating a second project around tooling.

  2. Load Shop and Brackets settings on the server

    Marketing can turn the Shop and Brackets sections on or off.

    Originally, the navigation checked those settings in the browser after the page had already loaded. That meant the Shop link could appear a moment late after every refresh.

    I could have hidden the flicker visually, but that would not have fixed the reason it happened.

    Instead, I moved those settings into the server-side load so the page already knows whether Shop and Brackets are active before the first render.

    That removed the flicker, removed two extra API calls from every page, and also fixed a quieter problem where the footer did not always know whether the Shop was enabled.

  3. Use live text instead of titles baked into images

    The design had RULES, TEAMS, BRACKETS, and SPONSORS built directly into the homepage images.

    They looked good in the mockup but came out blurry when the images scaled. A larger image export would only fix one screen size.

    I rebuilt those titles as live text instead.

    I measured the placement from the design and matched the same proportions so the text stayed in the same visual position across different screen sizes.

    Now the titles stay sharp, can scale with the layout, and can also be read by screen readers.

  4. Scale the buttons with the layout instead of copying one fixed Figma size

    The design called for a 265 by 83 pixel button.

    That works at the exact screen size the mockup was designed for. It does not work everywhere else. At some widths it becomes too large. At others it feels too small.

    Instead of locking it to one fixed size, I kept the same proportions and sized it relative to the tile.

    That keeps the button visually consistent from smaller laptops up through large desktop screens.

Someone else's release process

Every change went through QA.

The tester would send back a spreadsheet with the problem, steps to reproduce it, and sometimes a screen recording.

The first rounds caught things like a missing profile icon, menus that stayed open after a link was tapped, and a footer that was not respecting the Shop setting.

Each one came back through the same cycle. Reproduce it. Find the cause. Fix it. Capture the before and after. Send it back through QA.

Some changes were less about bugs and more about making the new design hold up properly.

The WE ARE ALL IN wordmark in the footer was being stretched beyond the resolution of the original image on large screens, so I replaced it with a higher-resolution version.

I also reduced the homepage image weight from about 3.5 MB to 1.8 MB without a visible change in quality.

Registration was just an email

The tournament sells out in about a day.

When they asked me to build registration for 2027, I went looking for what existed. There was a form on the teams page that collected five fields and emailed them to a staff address. Nothing was stored. Someone read the email and typed the team into the admin by hand.

So this was not reviving something. It was building it.

A black iPhone 18 Pro, angled, showing the Register for 2027 page with the dates, cost, payment and uniforms table.
Register for 2027, on a phone. Most coaches register from a phone.

Building the form

The form went through staging in versions. Spots change with the division, and the submit button stays off until November 1.

An earlier version of the 2027 form, saying each age group has 12 team spots, with a greyed-out Registration Opens November 1 button at the bottom.

Earlier · Step 1 of 3

Every age group with 12 team spots

An earlier version on the dev site. Every age group had the same number of spots, and the button at the bottom reads “Registration opens November 1”.

The next version of the form, saying 8U and 14U have 12 team spots and 9U through 13U have 32.

Earlier · Step 2 of 3

12 for 8U and 14U, 32 for 9U to 13U

Spots change with the division (12 for 8U and 14U, 32 for 9U to 13U). The submit button stays off until November 1.

The form showing the American and National division choice for 11U.
The form showing the American and National division choice for 11U.

Now · Step 3 of 3

9U to 13U pick their own level

9U to 13U choose American or National themselves, with the tournament’s description of each. 8U and 14U never see this.

Registrations are saved to the database rather than only emailed, and a team cannot register twice.

Most coaches register from a phone.

Close up

Step 1 of 3

The navigation at version 2.0.94 — a white bar with the PROLOOK, UVU and Autism Council of Utah logos, a Donate Here button, a large ALL IN wordmark, Login and a menu button.
Before, at 2.0.94, before any of my work. No route to registration at all.
The navigation with Register for 2027 added.
After. Donate Now, Shop, Register for 2027 across the top, with Register for 2027 also first under Tournament Info, on desktop and on a phone.

What the site should decide

The tournament director wanted to pick which teams got in. Their own form said first come, first served.

I raised it once, then built what he asked for, because which teams play is his call and not mine. What I could do was make the consequences visible: a board that shows each division against its cap, so accepting a seventeenth team into a sixteen-team division is not possible by accident, and a waitlist that keeps the order teams registered in, so the February deadline has an answer ready when someone does not pay.

The part I pushed back on was the interface. He asked for drag and drop. He will be using it on a phone, on the first of November. Dragging a card on a phone, in that hour, is worse than tapping a button. I built buttons, and said I would revisit it after he had used it for real.

The staff board

What the tournament director sees. Sample teams, not real ones.

The staff registrations screen, a count against the cap for each division above a table of sample registrations with status and deposit columns.

First version · Step 1 of 2

Every registration in one place

Staff can see every registration, how full each division is against its own cap, approve or decline a team, tick off the deposit when it arrives, search, filter, and export the whole list to a spreadsheet.

The staff registrations board, one division at a time, with accepted teams on the left and teams waiting on the right.
The staff registrations board, one division at a time, with accepted teams on the left and teams waiting on the right.

Now · Step 2 of 2

One division at a time, against the cap

Accept, waitlist or decline, singly or several at once, and send the acceptance emails in one go.

Filter by who needs uniforms, who still owes a deposit, who played last year, who is new, and who has not been emailed.

Overrides for when something goes wrong: resend an email, correct an address, put a team on the site early, or remove a registration so they can start again.

Built for a phone, because that is where he will be on the day.

Step 1 of 2

The emails are the product

The form was a fifth of the work. What mattered was what happened after someone pressed submit.

Three emails: a receipt to the coach that says plainly that registering does not reserve a spot, a notice to the tournament with every contact detail and a link straight to the board, and the acceptance email carrying the Venmo code and a card payment link with that team’s own division and name written into the instructions, so a two hundred dollar payment can be matched to a team without anyone guessing.

Two things I got wrong on the first pass and caught before anyone saw them.

The images were linked using the address of the incoming request, which comes out as localhost behind the server’s proxy — every email would have arrived with a broken Venmo code, which is the one thing that email exists to carry.

And the emails were being sent before the page answered, so a coach would have sat watching a spinner while two mail servers took their time. On the first of November, with everyone submitting at once, that is how you get duplicate registrations. The form now answers in a third of a second and the emails follow behind it.

  • The confirmation email a coach receives after registering.

    Sent the moment a coach registers. Says plainly that the form does not reserve a spot.

  • The acceptance email, with Venmo and card payment options.

    Sent when staff accept a team. The division and team name are filled in for them, so the payment can be matched.

  • The notification the tournament receives when a team registers.

    What the tournament gets, with a link straight to the board.

Testing a one-day sellout

Registration opens on the first of November and the tournament sells out that day. There is no second attempt.

So the form unlocks itself on the test sites and stays shut on the live site until the date, which meant QA could run the whole flow while the public page still said “Registration opens November 1”. The notification that normally goes to the tournament director goes back to whoever filled in the form when it is sent from a test site, so testing it fifty times does not put fifty fake teams in his inbox.

What's next

Pages built ahead of their launch, not live yet. Each one carries a preview banner, and the products and prices are placeholders.

A preview of the Shop Team Flags page — a flag preview panel beside division buttons, a team name dropdown, quantity and an Order Now button, under a yellow "Preview only, products and prices are placeholders" banner.
A preview of the Shop Team Flags page — a flag preview panel beside division buttons, a team name dropdown, quantity and an Order Now button, under a yellow "Preview only, products and prices are placeholders" banner.

Preview · Step 1 of 3

Shop team flags

Pick a division, then the team, then a quantity. The flag preview fills in from the choices.

A preview of the Tournament Swag page — an ALL IN T-shirt and an ALL IN hat with photo-coming-soon placeholders and Pre-order Now buttons.
A preview of the Tournament Swag page — an ALL IN T-shirt and an ALL IN hat with photo-coming-soon placeholders and Pre-order Now buttons.

Preview · Step 2 of 3

Tournament swag

A T-shirt and a hat to pre-order and pick up at the tournament.

A preview of an earlier Register for 2027 page — a single Team Registration card with head parent contact fields and a pre-order swag checkbox, under a "Preview only, registration isn't open yet" banner.
A preview of an earlier Register for 2027 page — a single Team Registration card with head parent contact fields and a pre-order swag checkbox, under a "Preview only, registration isn't open yet" banner.

Preview · Step 3 of 3

An earlier registration page

An earlier take on registration, with a head parent contact and a box to pre-order swag. The form shown above replaced it.

Step 1 of 3

My role

I was the frontend developer on the marketing side.

My job was the front end of the redesign, built from the designer’s Figma files and shipped through the existing DEV, staging, QA, and release process.

Most of my work was in Svelte and Tailwind.

I rebuilt the navigation, homepage, footer, and shared components, then worked through QA issues as they came back.

A few changes also touched how page data was loaded on the server when the front end needed information before the page rendered.

Engineering owned the application itself, including the API, bracket logic, team management, and production releases.

I did not build those systems.

The Shop bug, rebuilt

Each version rebuilt from git history and run as a production build. The difference is where you end up, not how the page looks.

  • Labeled: before, v2.0.99, what a visitor sees first — the navigation without a Shop link.

    2.0.99, the first thing a visitor sees has no Shop link

  • Labeled: after, v2.0.100, what a visitor sees first — the Shop link is already there.

    2.0.100, the Shop link is already there

  • Labeled: before, v2.0.100, I opened the Shop link in a new tab and ended up on the home page.

    2.0.100, Shop in a new tab lands on the home page

  • Labeled: after, v2.0.102, I opened the Shop link in a new tab and ended up on the Shop, loading.

    2.0.102, the new tab opens the Shop

  • Labeled: before, v2.0.100, I clicked Shop, then reloaded the page, and ended up on the home page.

    2.0.100, reloading the Shop lands on the home page

  • Labeled: after, v2.0.102, I clicked Shop, then reloaded the page, and stayed on the Shop.

    2.0.102, reloading stays on the Shop

Passed every test, broke the Shop

I fixed a flickering Shop link, every test passed, and it still broke the Shop on the live site because the page trusted a value the server was sharing between visitors.

Problem

Right after the Shop flicker fix shipped, QA found another problem. Opening Shop in a new tab or reloading the Shop page sent the user back to the homepage.

Clicking Shop normally from the homepage still worked. That made it look random.

First assumption

The frustrating part was that I had already tested it.

Before the release, I opened Shop from the Rules and Sponsors pages on my local server and landed on Shop every time. Same code. Same data. Clean pass.

Because it worked locally but failed after deployment, I assumed something in the live environment, probably caching, was behaving differently.

What I found

The problem was not actually the Shop link.

The Shop page had a guard that checked a stored value before allowing the page to load. Only the homepage was setting that value.

The bigger problem was that the value lived in server state that was shared between visitors. Once somebody loaded the homepage, that value became active and made later tests pass even when the logic was wrong.

The old navigation code had also been setting that value on every page as a side effect. When I removed that code to fix the flicker, I exposed the older bug underneath it.

There was even an old note above the guard saying:

“fix redirection bug cannot visit page”

The redirect had been worked around before, but the dependency was still there.

Fix

I changed the Shop guard so it used the activation flag the server already loads for every request.

That is the same source of truth used by the navigation and footer. The actual change was only a few lines.

I could have put the old navigation behavior back, but that would have brought the flicker back and kept the Shop dependent on whatever state happened to be loaded on the server.

The Shop guard uses the activation flag the server already loads for every request.JavaScript
// src/routes/shop/+page.server.js
import { redirect } from '@sveltejs/kit';

// Read the flag per request, not from a shared value.
export const load = async ({ locals }) => {
  if (!locals.flags.shopActive) throw redirect(307, '/');
  return {};
};
The same source of truth used by the navigation and footer.Svelte
<script>
  // Use the same flag as the Shop guard and the footer.
  export let data;
</script>

{#if data.flags.shopActive}
  <a href="/shop">Shop</a>
{/if}

How I verified it

My local development server could not reliably reproduce the bug, so I stopped using it as proof.

I built the application for production and ran it on a fresh server without opening the homepage first. That finally reproduced the real behavior. The old build redirected away from the Shop. The fixed build opened it correctly.

Then I went through every case from QA’s sheet:

  • Open Shop in a new tab
  • Reload while already on Shop
  • Open Shop from the homepage
  • Open Shop from Rules
  • Open Shop from Sponsors
  • Check navigation and footer links
  • Turn Shop off and confirm the redirect still happens when it should

After that, I repeated the checks on staging before the next release.

Result

The experience works better for the people actually using it during the tournament, especially on mobile.

Parents can get to brackets. Coaches can reach rules. Team managers can get to the Shop.

Marketing also has someone on the front-end side who can make updates without every request waiting on an engineering team working in another timezone.

Teams now have a real way to register for 2027, and staff have a board to decide who plays.

I do not have access to the site’s analytics, so there is no traffic or conversion number here. I would rather say that than invent one.

What I can stand behind is that the redesign shipped through four production releases, the major navigation and Shop issues were fixed, and the site is much easier to use and maintain than where it started.

What I'd do differently

When I removed the navigation’s old Shop check, I should have searched the rest of the project for anything else depending on it.

There was exactly one other place. It already had a TODO note sitting above it.

That search would have taken a minute and probably saved the production bug.

I would also test layout issues on a real phone earlier. At one point I spent hours chasing a mobile layout problem that only existed inside a simulated browser. On an actual phone, the page was fine.

Now I treat browser simulation as useful, but not proof.

Full stack

Front end
  • Svelte
  • SvelteKit
  • Tailwind CSS
  • JavaScript
  • HTML
  • HTML email
Runtime and tooling
  • Node
  • Volta
  • npm
Development process
  • DEV
  • Staging
  • Production
  • QA testing
  • Git / GitHub
Design and optimization
  • Figma
  • Responsive layout work
  • Image optimization
  • Accessibility improvements