Skip to main content
The tournament components handle tournament creation, team management, bracket visualization, and multi-stage tournament formats including single elimination, double elimination, Swiss, and round-robin.

Core Tournament Components

TournamentForm

Primary component for creating and editing tournaments with full match options integration. Location: components/tournament/TournamentForm.vue Key Features:
  • Tournament name and description
  • Start date/time picker with calendar
  • Auto-start configuration
  • Discord notifications toggle
  • Full match options (map pool, veto, coaches, etc.)
  • Custom map pool support
Usage Example:
<template>
  <TournamentForm 
    :tournament="existingTournament" 
    @updated="handleUpdate" 
  />
</template>

<script setup>
import TournamentForm from '~/components/tournament/TournamentForm.vue'

const existingTournament = ref(null) // null for create mode

function handleUpdate() {
  // Refetch tournament data
}
</script>
Props:
  • tournament (Object, optional): Existing tournament for editing
Events:
  • updated: Emitted after successful create/update
Form Fields:
{
  name: string,              // Tournament name (required)
  description: string,       // Tournament description
  start: Date,              // Start date/time (must be future)
  auto_start: boolean,      // Auto-start when scheduled
  discord_notifications_enabled: boolean,
  // ... inherits all MatchOptions fields
}

TournamentStage

Wrapper component that routes to appropriate bracket viewer based on stage type. Location: components/tournament/TournamentStage.vue Key Features:
  • Automatic format detection (Swiss vs Bracket)
  • Group support (A, B, C, etc.)
  • Loser bracket handling for double elimination
  • Dynamic round label generation
Usage Example:
<template>
  <TournamentStage
    :stage="stage"
    :tournament="tournament"
    :is-final-stage="isFinalStage"
  />
</template>

<script setup>
import TournamentStage from '~/components/tournament/TournamentStage.vue'

const stage = ref({
  id: 'stage-uuid',
  type: 'SingleElimination',
  groups: 2,
  brackets: [...]
})
</script>
Props:
  • stage (Object, required): Stage object with type, groups, brackets
  • tournament (Object, required): Parent tournament object
  • isFinalStage (Boolean, required): Whether this is the final stage
Stage Types:
enum e_tournament_stage_types_enum {
  SingleElimination,
  DoubleElimination,
  Swiss,
  RoundRobin
}

TournamentBracketViewer

Advanced bracket visualization with zoom, pan, minimap, and fullscreen support. Location: components/tournament/TournamentBracketViewer.vue Key Features:
  • Interactive pan and zoom (Ctrl+Scroll or buttons)
  • Minimap navigation for large brackets
  • Fullscreen mode
  • Momentum scrolling with smooth deceleration
  • SVG connecting lines between matches
  • Winner and loser bracket connections
  • Responsive height based on number of groups
  • Touch support for mobile devices
Usage Example:
<template>
  <TournamentBracketViewer
    :stage="stage"
    :tournament="tournament"
    :rounds="roundsMap"
    :is-final-stage="true"
    :is-loser-bracket="false"
    :total-groups="2"
    :stage-type="'SingleElimination'"
  />
</template>

<script setup>
import TournamentBracketViewer from '~/components/tournament/TournamentBracketViewer.vue'

// Group brackets by round
const roundsMap = computed(() => {
  const rounds = new Map()
  stage.value.brackets.forEach(bracket => {
    if (!rounds.has(bracket.round)) {
      rounds.set(bracket.round, [])
    }
    rounds.get(bracket.round).push(bracket)
  })
  return rounds
})
</script>
Props:
  • stage (Object, required): Tournament stage
  • tournament (Object, required): Tournament object
  • rounds (Map, required): Brackets grouped by round number (Map of number to Array)
  • isFinalStage (Boolean, default: false): Is this the final stage
  • isLoserBracket (Boolean, default: false): Is this a loser bracket
  • totalGroups (Number, default: 1): Total number of groups
  • stageType (String, default: null): Stage type enum value
Controls:
  • Zoom In/Out: Click buttons or Ctrl+Scroll
  • Reset Zoom: Click percentage button
  • Pan: Click and drag on bracket
  • Minimap: Click or drag to navigate (shows when 4+ rounds)
  • Fullscreen: Toggle fullscreen mode
Dynamic Features:
// Zoom levels
const MIN_ZOOM = 0.5
const MAX_ZOOM = 3.0
const ZOOM_STEP = 0.1
const DEFAULT_ZOOM = 0.75

// Momentum scrolling
const MOMENTUM_DECAY = 0.95
const MOMENTUM_MIN_VELOCITY = 0.5

// Height based on groups
maxHeight = totalGroups === 1 ? '80vh' : 
            totalGroups === 2 ? '40vh' : 
            totalGroups === 3 ? '28vh' : '22vh'

SwissBracketViewer

Specialized viewer for Swiss format tournaments showing record-based grouping. Location: components/tournament/SwissBracketViewer.vue Key Features:
  • Record pool grouping (3-0, 2-1, 1-2, 0-3)
  • Round progression display
  • Automatic bracket connections
  • Team record tracking

TournamentMatch

Displays a single match within a tournament bracket. Location: components/tournament/TournamentMatch.vue Key Features:
  • Team names and seeds
  • Current score display
  • Match status indicator
  • Schedule dialog trigger
  • Winner highlighting
  • TBD team placeholders
Usage Example:
<template>
  <TournamentMatch
    :stage="stage"
    :tournament="tournament"
    :round="roundNumber"
    :brackets="roundBrackets"
    @schedule-bracket="openScheduleDialog"
  />
</template>

<script setup>
import TournamentMatch from '~/components/tournament/TournamentMatch.vue'

function openScheduleDialog(bracket) {
  // Open schedule dialog for bracket
}
</script>
Props:
  • stage (Object, required)
  • tournament (Object, required)
  • round (Number, required)
  • brackets (Array, required): Brackets in this round
Events:
  • schedule-bracket: Emitted when schedule button clicked

Team Management Components

TournamentTeam

Displays and manages a tournament team roster. Location: components/tournament/TournamentTeam.vue Key Features:
  • Team name and logo
  • Player roster with roles
  • Captain indicator
  • Invite players
  • Remove players (captain/organizer)
  • Leave team

TournamentTeamMemberRow

Single team member row with actions. Location: components/tournament/TournamentTeamMemberRow.vue Features:
  • Player display with stats
  • Role assignment
  • Promote to captain
  • Remove from team

TournamentTeamInvite

Invite players to join a tournament team. Location: components/tournament/TournamentTeamInvite.vue Features:
  • Player search
  • Bulk invitations
  • Pending invite list

Tournament Administration

TournamentStageBuilder

Admin interface to create and configure tournament stages. Location: components/tournament/TournamentStageBuilder.vue Key Features:
  • Stage type selection
  • Number of groups configuration
  • Team advancement rules
  • Best-of configuration per round
  • Stage ordering
Usage Example:
<template>
  <TournamentStageBuilder
    :tournament="tournament"
    @stage-created="refetchTournament"
  />
</template>

TournamentStageForm

Form for creating/editing a single tournament stage. Location: components/tournament/TournamentStageForm.vue Form Fields:
{
  type: e_tournament_stage_types_enum,
  name: string,
  groups: number,
  teams_per_group: number,
  advancement: {
    winners: number,  // Teams advancing to next stage
    losers: number    // Teams going to loser bracket
  }
}

StageRoundBestOfConfig

Configure best-of settings per round in a stage. Location: components/tournament/StageRoundBestOfConfig.vue Usage Example:
<template>
  <StageRoundBestOfConfig
    :stage="stage"
    :rounds="['Quarter Finals', 'Semi Finals', 'Grand Finals']"
  />
</template>
Features:
  • Per-round best-of selection (BO1, BO3, BO5)
  • Visual round progression
  • Bulk configuration

Tournament Display Components

TournamentTableRow

Single tournament row in browse/listing tables. Location: components/tournament/TournamentTableRow.vue Displays:
  • Tournament name and description
  • Start date/time
  • Team count
  • Status badge
  • Join/View buttons

SimpleTournamentDisplay

Compact tournament card for listings. Location: components/tournament/SimpleTournamentDisplay.vue Features:
  • Tournament poster image
  • Name and date
  • Quick actions

TournamentResults

Final tournament results and placements. Location: components/tournament/TournamentResults.vue Displays:
  • Final standings (1st, 2nd, 3rd, etc.)
  • Team names and rosters
  • Prize information (if configured)
  • Match history

RoundRobinResults

Results table for round-robin stages. Location: components/tournament/RoundRobinResults.vue Features:
  • Wins/Losses/Ties table
  • Head-to-head records
  • Tiebreaker information
  • Points calculation

Tournament Dialogs

BracketScheduleDialog

Dialog for scheduling a bracket match. Location: components/tournament/BracketScheduleDialog.vue Usage Example:
<template>
  <BracketScheduleDialog
    :open="dialogOpen"
    :bracket="selectedBracket"
    @update:open="dialogOpen = $event"
  />
</template>

<script setup>
import BracketScheduleDialog from '~/components/tournament/BracketScheduleDialog.vue'

const dialogOpen = ref(false)
const selectedBracket = ref(null)
</script>
Props:
  • open (Boolean): Dialog visibility
  • bracket (Object): Bracket to schedule
Events:
  • update:open: Emits when dialog should close

TournamentJoinForm

Dialog for joining a tournament (create team or join existing). Location: components/tournament/TournamentJoinForm.vue Features:
  • Create new team option
  • Join existing team with invite code
  • Team name validation

Tournament Notifications

TournamentNotifications

Real-time tournament notifications and updates. Location: components/tournament/TournamentNotifications.vue Features:
  • Match scheduled notifications
  • Match starting soon alerts
  • Tournament stage changes
  • Team invitation notifications
  • Advancement notifications

Organizer Components

TournamentOrganizers

Manage tournament organizers and permissions. Location: components/tournament/TournamentOrganizers.vue Features:
  • Add/remove organizers
  • Permission levels
  • Organizer list

TournamentOrganizerRow

Single organizer row with actions. Location: components/tournament/TournamentOrganizerRow.vue

TournamentServerRow

Assigned server row for tournament matches. Location: components/tournament/TournamentServerRow.vue

Round Label Utilities

The tournament components use intelligent round labeling:
import { getRoundLabel } from '~/utilities/tournamentRoundLabels'

// Example labels
getRoundLabel(1, 1, true, 8, false, 'SingleElimination', false)
// Returns: { key: 'tournament.round.quarter_finals', params: {} }

getRoundLabel(3, 2, true, 2, false, 'DoubleElimination', true)
// Returns: { key: 'tournament.round.grand_finals', params: {} }

getRoundLabel(2, 1, false, 16, true, 'DoubleElimination', false)
// Returns: { key: 'tournament.round.losers.round_x', params: { round: 2 } }
Label Types:
  • Grand Finals
  • Finals
  • Semi Finals
  • Quarter Finals
  • Round of 16/32/64
  • Winners/Losers Round X
  • Round X (generic)

Tournament Data Flow

Tournament Structure

interface Tournament {
  id: string
  name: string
  description: string
  start: Date
  auto_start: boolean
  status: e_tournament_status_enum
  options: MatchOptions
  stages: TournamentStage[]
  teams: TournamentTeam[]
}

interface TournamentStage {
  id: string
  tournament_id: string
  type: e_tournament_stage_types_enum
  order: number
  groups: number
  brackets: Bracket[]
}

interface Bracket {
  id: string
  stage_id: string
  round: number
  group: number
  match_id?: string
  parent_bracket_id?: string
  loser_bracket_id?: string
  team_1_id?: string
  team_2_id?: string
  team_1_seed?: number
  team_2_seed?: number
}

GraphQL Integration

Tournament components use subscriptions for real-time updates:
<script lang="ts">
import { typedGql } from '~/generated/zeus/typedDocumentNode'
import { $ } from '~/generated/zeus'

export default {
  apollo: {
    $subscribe: {
      tournament: {
        query: typedGql('subscription')({
          tournaments_by_pk: [
            { id: $('id', 'uuid!') },
            {
              id: true,
              name: true,
              status: true,
              stages: [{ order_by: [{ order: 'asc' }] }, {
                id: true,
                type: true,
                brackets: [{ order_by: [{ round: 'asc' }] }, {
                  id: true,
                  match: { /* ... */ }
                }]
              }]
            }
          ]
        }),
        variables() {
          return { id: this.$route.params.id }
        }
      }
    }
  }
}
</script>

Bracket Algorithms

The bracket viewer implements sophisticated algorithms:

Connecting Lines

SVG paths connect parent and child brackets:
function drawLine(
  svg: SVGElement,
  sourceEl: HTMLElement,
  targetEl: HTMLElement,
  type: 'winner' | 'loser'
) {
  const sourceX = sourceEl.offsetLeft + sourceEl.offsetWidth
  const sourceY = sourceEl.offsetTop + sourceEl.offsetHeight / 2
  const targetX = targetEl.offsetLeft
  const targetY = targetEl.offsetTop + targetEl.offsetHeight / 2
  
  const midX = (sourceX + targetX) / 2
  
  // Create stepped path
  const path = `M ${sourceX} ${sourceY} H ${midX} V ${targetY} H ${targetX}`
  
  // Winner lines: white, Loser lines: red
  const color = type === 'winner' ? 'white' : 'rgba(255, 100, 100, 0.7)'
}

Zoom and Pan

Transform-based zoom with scroll position preservation:
const zoomLevel = ref(0.75)

function zoomIn() {
  zoomLevel.value = Math.min(MAX_ZOOM, zoomLevel.value + ZOOM_STEP)
  nextTick(() => {
    redrawLines() // Recalculate SVG paths
  })
}

Match Components

Individual match management and display

UI Components

Base UI components and design system

Next Steps

Tournament API

GraphQL mutations and queries for tournaments

Creating Tournaments

Learn how to configure tournament stages

Build docs developers (and LLMs) love