Josh Bruce Online

The Button - Collaborative Timer Game Documentation

Overview

“The Button” is a multiplayer social experiment game inspired by Reddit’s famous r/thebutton April Fools’ experiment. Players collaborate to prevent a countdown timer from reaching zero by pressing a central button, with each press resetting the timer and earning the player a spot on the leaderboard with a color corresponding to when they pressed the button.

Technical Architecture

Core Technologies

File Structure

button/
├── index.html    # Main game application
├── cnfg.js       # Firebase configuration file
└── favicon.ico   # Site icon (referenced but not documented)

Game Mechanics

Core Countdown System

// 12-hour countdown timer
const maxSeconds = 12 * 60 * 60;  // Total seconds in 12 hours
let timerFinishTime;              // Absolute finish time
let colour = '';                  // Current button color based on remaining time

// Timer calculation based on last button press
timerFinishTime = timestamp + (12 * 60 * 60 * 1000);  // 12 hours from last press

Color-Coded Urgency System

// Progressive color zones based on remaining time percentage
const gradientSections = [
    { colour: '#6F41B1', range: 0.7 },    // Purple - 70-100% remaining
    { colour: '#4D86F7', range: 0.45 },   // Blue   - 45-70% remaining
    { colour: '#4CA84C', range: 0.25 },   // Green  - 25-45% remaining
    { colour: '#F6BD44', range: 0.13 },   // Yellow - 13-25% remaining
    { colour: '#DC6C33', range: 0.05 },   // Orange - 5-13% remaining
    { colour: '#E14331', range: 0.0 },    // Red    - 0-5% remaining
];

// Dynamic color assignment based on timer percentage
for (const section of gradientSections) {
    if (percentage >= section.range) {
        colour = section.colour;
        break;
    }
}

Firebase Integration

Database Configuration

// Firebase Realtime Database setup
const firebaseConfig = {
    apiKey: "AIzaSyChiGyL3rORNm5AVZ632wN92AqfhDKfNDs",
    authDomain: "joshbruceonline-button.firebaseapp.com",
    databaseURL: "https://joshbruceonline-button-default-rtdb.europe-west1.firebasedatabase.app",
    projectId: "joshbruceonline-button",
    storageBucket: "joshbruceonline-button.appspot.com",
    messagingSenderId: "1066626412012",
    appId: "1:1066626412012:web:cba79f7dbf59a194a4e4c9"
};

Database Schema

// Firebase Realtime Database structure
{
  "leaderboard": {
    "[entryId]": {
      "name": "PlayerName",           // Player display name (max 5 chars)
      "score": 25200,                 // Seconds remaining when pressed
      "colour": "#4D86F7",            // Color zone when pressed
      "timestamp": 1643723400000      // Server timestamp of button press
    }
  }
}

Real-time Leaderboard Synchronization

// Listen for real-time leaderboard updates
const leaderboardRef = firebase.database().ref("leaderboard");
leaderboardRef.on("value", function (snapshot) {
    const leaderboardEntries = [];
    
    snapshot.forEach(function (childSnapshot) {
        const entry = childSnapshot.val();
        leaderboardEntries.push(entry);
    });
    
    // Sort by score in descending order (longest waits first)
    leaderboardEntries.sort(function (a, b) {
        return b.score - a.score;  // Note: Original has bug (+ instead of -)
    });
    
    updateLeaderboardDisplay(leaderboardEntries);
});

User Interface Design

Central Button Design

/* Prominent circular button with dynamic borders */
button {
    background-color: #B1B1B1;
    color: white;
    padding: 100px 100px;         /* Large clickable area */
    font-size: 18px;
    cursor: pointer;
    border-radius: 50%;           /* Perfect circle */
    display: block;
    margin: 0 auto;
}

/* Active state feedback */
button:active {
    background-color: #9B9D9E;    /* Darker on press */
}

/* Dynamic color border system */
const borderStyle = `
    0 0 0 10px #909090,           /* Inner gray border */
    0 0 0 17px #DEDEDE,           /* Middle light border */
    0 0 0 27px ${colour}          /* Outer color-coded border */
`;
button.style.boxShadow = borderStyle;

Visual Progress Indicator

/* Color-coded progress bar reflecting time zones */
.status-bar {
    height: 40px;
    background-color: #ccc;
    border-radius: 20px;
    overflow: hidden;
    position: relative;
    /* Rainbow gradient background matching color zones */
    background-image: linear-gradient(to right, 
        #6F41B1 0%, #6F41B1 30%,     /* Purple zone */
        #4D86F7 30%, #4D86F7 55%,    /* Blue zone */
        #4CA84C 55%, #4CA84C 75%,    /* Green zone */
        #F6BD44 75%, #F6BD44 87%,    /* Yellow zone */
        #DC6C33 87%, #DC6C33 95%,    /* Orange zone */
        #E14331 95%, #E14331 100%    /* Red zone */
    );
}

/* Moving indicator line */
#status-line {
    height: 100%;
    background-color: black;
    width: 3px;
    position: absolute;
    top: 0;
    right: 0;
    transition: right 1s linear;     /* Smooth movement animation */
}

Content Moderation System

Name Validation and Filtering

// Comprehensive banned words list
const bannedNamesString = "cock,balls,ballz,pussy,fuck,shit,cunt,suck,bitch,nig,penis,france,french,fag,kill,uh,ass,arse,nonce,piss,pedo,slut,whore,twat,ret,ard,hate,gay,ligma,slay,tran,gun";
const bannedNames = bannedNamesString.split(",");

// Case-insensitive substring matching
function isNameBanned(name, bannedNames) {
    const lowercaseName = name.toLowerCase();
    for (const bannedName of bannedNames) {
        if (lowercaseName.includes(bannedName)) {
            return true;
        }
    }
    return false;
}

// Client-side validation
if (name.length > 5) {
    alert("Names can't be more than 5 characters in length!");
    return;
}

if (isNameBanned(name, bannedNames)) {
    alert("Names will be displayed on the leaderboard. This name includes restricted words! Please enter another name.");
    return;
}

Server-side Data Cleanup

// Automatic deletion of invalid entries
function deleteLongNames() {
    const leaderboardRef = firebase.database().ref("leaderboard");
    
    leaderboardRef.once("value", function (snapshot) {
        snapshot.forEach(function (childSnapshot) {
            const entry = childSnapshot.val();
            const entryKey = childSnapshot.key;
            
            if (entry.name.length > 5) {
                leaderboardRef.child(entryKey).remove();
            }
        });
    });
}

// Real-time validation for new entries
firebase.database().ref("leaderboard").on("child_added", function (snapshot) {
    const entry = snapshot.val();
    const entryKey = snapshot.key;
    
    if (entry.name.length > 5) {
        firebase.database().ref("leaderboard").child(entryKey).remove();
    }
});

Timer and Synchronization System

Real-time Timer Updates

function incrementTimer() {
    const currentTime = new Date().getTime();
    const timeDiff = timerFinishTime - currentTime;
    
    if (timeDiff > 0) {
        const secondsLeft = Math.floor(timeDiff / 1000);
        const hours = Math.floor(secondsLeft / 3600);
        const minutes = Math.floor((secondsLeft % 3600) / 60);
        const seconds = secondsLeft % 60;
        
        // Display formatted time
        const shownTime = `${hours} Hours ${minutes} Minutes ${seconds} Seconds left`;
        document.getElementById("shown-time").innerText = shownTime;
        
        updateStatusBar();  // Update visual progress
    } else {
        clearInterval(timerInterval);
        // Timer expired - button "dies"
    }
}

// Update every second
const timerInterval = setInterval(incrementTimer, 1000);

Countdown Refresh from Database

function refreshCountdown() {
    database
        .ref("leaderboard")
        .orderByChild("timestamp")
        .limitToLast(1)                  // Get most recent button press
        .once("value")
        .then(function (snapshot) {
            snapshot.forEach(function (childSnapshot) {
                const entry = childSnapshot.val();
                const timestamp = entry.timestamp;
                
                if (timestamp) {
                    // Calculate new finish time (12 hours from last press)
                    timerFinishTime = timestamp + (12 * 60 * 60 * 1000);
                    
                    const secondsLeft = Math.floor((timerFinishTime - Date.now()) / 1000);
                    timerValue.innerText = formatTime(secondsLeft);
                }
            });
        });
}

Button Press Interaction

User Input and Data Submission

button.addEventListener("click", function () {
    const name = prompt("Enter your name:");
    const score = parseInt(timerValue.innerText);  // Current remaining seconds
    
    if (name && isValidName(name)) {
        const database = firebase.database();
        const serverTimestamp = firebase.database.ServerValue.TIMESTAMP;
        
        // Submit button press to Firebase
        database.ref("leaderboard").push({
            name: name,
            score: score,                    // Seconds remaining when pressed
            colour: colour,                  // Current color zone
            timestamp: serverTimestamp       // Server-side timestamp
        });
        
        button.disabled = false;
    }
});

Time Formatting Utilities

function formatTime(seconds) {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const remainingSeconds = seconds % 60;
    return `${hours} hours, ${minutes} minutes, ${remainingSeconds} seconds`;
}

Visual Status Bar System

Progress Bar Calculation

function updateStatusBar() {
    const secondsLeft = parseInt(timerValue.innerText);
    const maxSeconds = 12 * 60 * 60;           // 12 hours total
    const percentage = (secondsLeft / maxSeconds);
    
    // Calculate position on progress bar
    const statusBarWidth = document.querySelector(".status-bar").offsetWidth;
    const statusLineWidth = document.querySelector("#status-line").offsetWidth;
    const rightPosition = (statusBarWidth - statusLineWidth) * percentage;
    
    // Move status line to correct position
    statusBar.style.right = rightPosition + "px";
    
    // Determine color zone and update button border
    determineColorZone(percentage);
}

Game Psychology and Mechanics

Social Experiment Design

The game implements several psychological mechanisms:

  1. Collective Responsibility: All players share the goal of keeping the button alive
  2. Risk vs Reward: Waiting longer for a better color vs ensuring survival
  3. Social Proof: Leaderboard showing successful “brave” players
  4. Urgency Creation: Visual countdown and color changes create pressure
  5. FOMO (Fear of Missing Out): Limited time windows for each color tier

Color Psychology Implementation

// Color meanings and psychological impact:
// Purple (#6F41B1) - Luxury, early safety (70-100% remaining)
// Blue (#4D86F7)   - Trust, moderate safety (45-70% remaining)
// Green (#4CA84C)  - Growth, balanced risk (25-45% remaining)
// Yellow (#F6BD44) - Caution, increasing tension (13-25% remaining)
// Orange (#DC6C33) - Warning, high risk (5-13% remaining)
// Red (#E14331)    - Danger, maximum urgency (0-5% remaining)

Security and Anti-Abuse Measures

Right-Click Context Menu Prevention

// Disable right-click context menu
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
});

Multiple Validation Layers

  1. Client-side validation: Immediate feedback for users
  2. Server-side cleanup: Automatic removal of invalid entries
  3. Real-time monitoring: Continuous validation of new submissions
  4. Content filtering: Comprehensive banned words system

Performance Characteristics

Optimization Features

Browser Compatibility

// Modern browser features required:
// - Firebase SDK v8.6.1 support
// - CSS box-shadow and transitions
// - JavaScript ES6 features (const, arrow functions)
// - Realtime Database WebSocket connections

Analytics Integration

Google Analytics Tracking

// Comprehensive usage analytics
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-WPNF0DNSMX');

Potential Tracking Events

Identified Code Issues

Critical Bug in Leaderboard Sorting

// BUG: Incorrect sorting operation
leaderboardEntries.sort(function (a, b) {
    return b.score + a.score;  // Should be: b.score - a.score
});

// This causes addition instead of comparison, breaking sort order

Minor Issues

  1. Inconsistent Timer Updates: Multiple timerValue.innerText assignments
  2. Redundant Button Enabling: button.disabled = false called unnecessarily
  3. Missing Error Handling: No try-catch blocks for Firebase operations
  4. Hard-coded Values: Magic numbers could be configurable constants

Social and Cultural Impact

Historical Context

Based on Reddit’s April Fools’ 2015 experiment “The Button,” which became a massive social phenomenon with:

Educational Value

  1. Social Psychology: Demonstrates collective action problems
  2. Game Theory: Illustrates prisoner’s dilemma variations
  3. Community Dynamics: Shows emergence of social structures
  4. Digital Sociology: Explores online behavioral patterns

Future Enhancement Opportunities

Gameplay Features

  1. Multiple Timers: Different difficulty levels with varying countdowns
  2. Team Mode: Faction-based gameplay with color loyalties
  3. Power-ups: Special abilities for certain color achievements
  4. Statistics Dashboard: Personal and global analytics
  5. Achievement System: Badges for various accomplishments

Technical Improvements

  1. Mobile Optimization: Responsive design for touch devices
  2. Real-time Chat: Social interaction during countdown
  3. Push Notifications: Alerts for critical countdown moments
  4. Progressive Web App: Offline functionality and app-like experience
  5. Advanced Analytics: Behavioral pattern analysis

Social Features

  1. User Profiles: Persistent player identities
  2. Historical Statistics: Long-term participation tracking
  3. Community Voting: Player-driven rule modifications
  4. Social Sharing: Integration with social media platforms
  5. Tournament Mode: Scheduled competitive events

Code Quality Assessment

Strengths

Areas for Enhancement

Conclusion

“The Button” represents a sophisticated implementation of a social experiment game that successfully captures the psychological tension and community dynamics of the original Reddit phenomenon. The technical implementation demonstrates strong understanding of real-time web applications, Firebase integration, and user experience design.

Technical Rating: 8.4/10

The application successfully creates an engaging social experience that combines technical excellence with psychological game design, making it both a technical achievement and a compelling social experiment.