_ _ ____ _____ _ _ __ ____ ___ __ ____ ____
( \( )( __)( _ )( \( ) /__\ ( _ \ / __) /__\ ( _ \( __)
) ( ) _) )(_)( ) ( /(__)\ ) /( (__ /(__)\ ) / ) _)
(_)\_)(____)(_____)(_)\_)(__)(__)(_)\_) \___)(__)(__)(_)\_)(____)
A zero-dependency, lightweight local-multiplayer strategy & skill arcade portal featuring 6 unique strategy, reflex, memory, and speed-typing arenas styled with a custom cyberpunk retro-synth UI.
Neon Arcade was born from a simple observation: modern casual web games have lost their immediacy. Many require heavy frameworks, external accounts, continuous internet connectivity, and invasive trackers just to play a quick round of Tic-Tac-Toe or Dots & Boxes with a friend sitting next to you.
I set out to build a completely self-contained, lightweight game portal that could run on any hardware without a backend or build tool. Initially, this project started as an individual internship project on web application development with Prodigy Infotech, focused on building a classic Tic-Tac-Toe system. However, realizing the potential of raw JavaScript and HTML5 to deliver immersive experiences, I upgraded it into a multi-layered gaming portal. I wanted to combine nostalgic local multiplayer mechanics with a striking retro-synth cyberpunk aesthetic, dynamic visuals, and fully synthesized real-time audio.
I am a developer-designer dedicated to the philosophy of zero-dependency, high-performance web engineering. I believe that rich visual experiences and engaging mechanics do not require massive framework dependencies. This project serves as a showcase of what is possible using raw DOM APIs, vanilla CSS custom properties, the Web Audio API, and HTML5 Canvas.
- State Preservation Without Databases: Sharing complex configurations (player names, custom avatars, color schemes, and round states) across completely separate HTML documents without a shared backend database.
- Real-time Synthesized Audio: Creating rich retro game sound effects dynamically on the client side without loading heavy MP3/WAV assets, which could delay page rendering.
- Double-Click Overlay Glitches: Fixing overlapping text rendering in the typing battle game where the startup overlay reference would become detached due to DOM cloning routines.
- Local Multiplication Layouts: Scaling grid systems (from 3x3 to 8x8) and turn layouts dynamically based on configurable player sizes (from 2 up to 8 players) while preserving strict responsiveness.
- The State System: I leveraged browser-native
sessionStorageto serialize player structures, custom colors, selected games, and round states as light JSON strings. This allowed seamless navigation between landing pages, customize screens, and individual game arenas. - The Audio System: I created a custom oscillator-based synthesizer engine (
AudioSynthesizer) using the Web Audio API. It programmatically generates frequencies, ADSR envelopes, and oscillator gains to synthesize ticks, click sounds, success fanfare, roll sweeps, and error alerts on the fly. - Visual Effects: I implemented a customized particle engine (
ParticleSystem) that draws interactive confetti on a floating HTML5 canvas using requestAnimationFrame loops, alongside scanline gradients and box-shadow neon glows. - The Core Architecture: I split each simulation into its own independent HTML/CSS/JS module, allowing modular expansion while maintaining a unified visual theme defined by shared CSS variables.
- Data Privacy: By design, all player configurations and scores remain entirely within the user's browser tab (
sessionStorage). No data is sent over the network, ensuring complete user privacy. - UX Directives: Every game includes an explicit "SYSTEM TIP" console at the bottom to teach users the mechanics immediately. Keyboard and mouse inputs are strictly locked during turn transitions to prevent race conditions or double-click bugs.
- Web Audio API Power: Synthesizing audio programmatically is incredibly efficient, resulting in zero network overhead and instant sound generation.
- Pure JavaScript Scalability: Well-structured vanilla JavaScript using ES6 classes and modules can easily handle complex state, canvas particles, and grid search algorithms without third-party frameworks.
- CSS Variable Choreography: Managing themes via CSS variables allows dynamic updating of player colors across entire layouts with a single
setAttributecall.
- Add support for local Bluetooth/Wi-Fi peer-to-peer multiplayer using WebRTC.
- Integrate a custom synthesizer configuration panel, allowing players to tweak oscillator shapes (sine, triangle, square, sawtooth) and filter frequencies.
- Develop 3 additional arenas: "Cyber Hacker Minesweeper", "Neon Snake Battle Arena", and "Matrix Code Breaker".
- Create a local leaderboard that persists across browser sessions using
localStorage.
"Neon Arcade is a tribute to the golden era of local multiplayer gaming, updated for the modern web. I hope playing it gives you the same adrenaline rush I got from engineering it. Crack the mainframe, override the systems, and crown the ultimate champion!"
- System Overview & Architecture
- Unified Styling & Design Tokens
- Core Systems & Shared Library
- The Six Game Arenas
- Detailed Technical Implementations & Code Walkthroughs
- Web Audio API Synthesis Reference
- Visual Effects & Keyframes Styling Reference
- Mermaid System Workflows
- Directory Structure
- Installation & Local Setup
- Server Configurations
- Configuration & Customization
- Deployment Guide
- Troubleshooting & Diagnostics
- Testing Documentation
- Security, Scalability & Privacy
- Frequently Asked Questions (FAQs)
- Licensing & Acknowledgments
Neon Arcade is designed as a modular collection of static pages. The system architecture is decoupled; pages are independent files that communicate via a shared interface schema stored in sessionStorage.
┌────────────────────────────────────────┐
│ index.html │
│ (Simulation Selection) │
└───────────────────┬────────────────────┘
│
▼ [Writes: selectedGame, playerCount]
┌────────────────────────────────────────┐
│ setup.html │
│ (Player Customization) │
└───────────────────┬────────────────────┘
│
▼ [Writes: players JSON]
┌────────────────────────────┼───────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ ttt.html │ │ dots.html │ │ dice.html │
│ (Tic-Tac-Toe) │ │ (Dots & Boxes) │ │ (Dice Race) │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│ │ │
└────────────────────────────┼───────────────────────────┘
┌────────────────────────────┼───────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ maze.html │ │ reflex.html │ │ time_attack.html │
│ (Maze Memory) │ │ (Reflex Arena) │ │ (Type Battle) │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│ │ │
▼ ▼ ▼
└────────────────────────────┴───────────────────────────┘
│
▼ [Reads: common.css, common.js]
┌────────────────────────────────────────┐
│ Core Shared Assets │
│ (Audio Synth, Confetti, HTML5) │
└────────────────────────────────────────┘
This decoupled modular architecture provides several benefits:
- Zero Build Time: Files can be served directly by any web server or loaded locally from disk.
- Resource Performance: The browser only loads the CSS and JavaScript files needed for the current game, keeping the memory footprint exceptionally low.
- Isolated State: Issues in one game cannot impact the execution or load behavior of other games.
Shared styling is governed by common.css. It establishes CSS Custom Properties (Variables) that define the visual theme:
| Design Token | Value | Visual Purpose |
|---|---|---|
--bg-dark |
#07040f |
Main background color |
--bg-surface |
rgba(18, 12, 36, 0.7) |
Translucent card glass panels |
--bg-surface-solid |
#120c24 |
Solid surface backing structures |
--border-color |
rgba(255, 255, 255, 0.08) |
Thin border divider |
--neon-blue |
#05d9e8 |
Cyber blue styling and alerts |
--neon-purple |
#b026ff |
Cyber purple branding glow |
--neon-green |
#39ff14 |
Successful hacks and correct actions |
--neon-yellow |
#f5ee30 |
Alert markers, system tips, warning states |
--neon-red |
#ff2a5f |
Failed operations, error key highlights |
--font-heading |
'Orbitron', sans-serif |
Tech monospace headings |
--font-sub |
'Rajdhani', sans-serif |
Tactical details |
--font-body |
'Inter', sans-serif |
High readability text |
- CRT Scanlines Grid: Added using
.scanlineswith a custom CSS linear gradient repeating background at low opacity (0.3) to simulate retro cathode-ray monitors. - Glassmorphism Panels: Applied via
backdrop-filter: blur(16px)and thin border overlays, producing a futuristic user interface. - Confetti Layer: A full-screen canvas
#celebration-canvasoverlays the page with absolute positioning andpointer-events: noneto show visual effects without intercepting clicks. - System Tips: The
.simulation-tip-boxat the bottom of each page acts as a console display panel using--neon-yellowtext-shadow highlights.
The file common.js contains the engine dependencies utilized across the application.
Rather than hosting audio assets, the synthesiser constructs nodes dynamically on the Web Audio context.
class AudioSynthesizer {
constructor() {
this.ctx = null;
}
init() {
if (!this.ctx) {
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
}
}
// Synthesize a retro tick sound
playTick() {
this.init();
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.type = 'sine';
osc.frequency.setValueAtTime(800, this.ctx.currentTime);
gain.gain.setValueAtTime(0.08, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.05);
osc.start();
osc.stop(this.ctx.currentTime + 0.05);
}
// Other functions: playSelect, playAction, playRoll, playWin, playFail, playScore, playPenalty
}When a simulation is won, ParticleSystem initiates rendering loops of 150 independent confetti shapes on the canvas.
Each particle utilizes physics models to govern its trajectory:
- Velocity Updates: $$\vec{v}{t} = \vec{v}{t-1} + \vec{g} \cdot \Delta t$$
- Position Updates: $$\vec{x}{t} = \vec{x}{t-1} + \vec{v}_{t} \cdot \Delta t$$
-
Wobble Effects: The horizontal offset is modified dynamically:
$$x_{\text{render}} = x_t + A \cdot \sin(\omega t + \phi)$$
This math results in realistic fluttering behavior as particles drift down the screen.
The system uses native helper functions to render scoreboards dynamically.
renderScoreboard(players, activeIndex): Wipes the score containers in the DOM, loops through the serialized list, generates SVG avatars based on configurations, and adds.activeborders to show whose turn it is.updateTurnIndicator(players, activeIndex): Changes the style values dynamically, updating the active player's name and glow colors across the screen.
- Files: ttt.html, ttt.css, ttt.js
- Concept: Classic matrix alignments upgraded to support multiple dimensions and player numbers.
The board scales dynamically according to player count:
-
2 Players:
$3 \times 3$ grid (Align$3$ to win) -
3 Players:
$4 \times 4$ grid (Align$3$ to win) -
4 Players:
$5 \times 5$ grid (Align$4$ to win) -
5-6 Players:
$6 \times 6$ grid (Align$4$ to win) -
7-8 Players:
$8 \times 8$ grid (Align$5$ to win)
To check if a player has won, the engine evaluates vectors from the coordinates
-
Vector Directions: Horizontal
$(0, 1)$ , Vertical$(1, 0)$ , Diagonal Main$(1, 1)$ , Diagonal Anti-Main$(1, -1)$ . -
Check Algorithm: Iterate along the vector path up to the required length (e.g.,
$L=4$ ). If all cells are occupied by the active player's index, victory is declared.
- Files: dots.html, dots.css, dots.js
- Concept: Spatial territory acquisition. Players take turns drawing horizontal or vertical lines between dots on a grid.
-
2 Players:
$4 \times 4$ dot grid ($3 \times 3$ boxes) -
3-4 Players:
$5 \times 5$ dot grid ($4 \times 4$ boxes) -
5-8 Players:
$6 \times 6$ dot grid ($5 \times 5$ boxes)
- A line is identified by its orientation (horizontal or vertical) and coordinate indices.
- When a line is selected, the engine checks the adjacent cells.
- If a cell's
$4$ surrounding borders are colored, that box is claimed by the player. - The player's avatar is rendered in the box, their score increases by
$1$ , and they receive an extra turn.
- Files: dice.html, dice.css, dice.js
- Concept: A 40-tile serpentine board race featuring special modifier tiles.
-
Boost Tiles (Green): Advances the player forward by
$3$ to$4$ extra tiles. -
Gravity Trap Tiles (Red): Drifts the player backward by
$3$ to$4$ tiles. - Warp Portal Tiles (Purple): Instantly swaps coordinates with the current race leader, adding dynamic swings to the competition.
The dice rolling animation is rendered dynamically:
- Coordinates are generated using random roll intervals.
- The dice element rotates rapidly on the screen before settling on the final rolled value (1 to 6).
- The engine then moves the player token step-by-step along the winding path.
- Files: maze.html, maze.css, maze.js
-
Concept: Focus memory runner on a
$6 \times 6$ matrix path.
- At the start of a turn, the grid runs a "Memory Scan" animation, flashing a random connected path of safe tiles from the bottom row to the top row.
- The path then disappears, and the active player must step on adjacent tiles to navigate through.
- If they select a correct tile, their position updates. If they select a wrong tile, the interface flashes red, plays a penalty sound, and resets their token back to the starting line.
- The first player to successfully exit the top row wins.
- Files: reflex.html, reflex.css, reflex.js
- Concept: A fast-paced reflex test.
- The central console flashes a random player's avatar after a variable delay (1.5 to 4 seconds).
- The target player must click their button as fast as possible.
-
Scoring Brackets:
- Reaction under
$300\text{ms}$ : +20 points - Reaction under
$600\text{ms}$ : +10 points
- Reaction under
- Penalties: Clicking early (False Start) or clicking another player's button deducts 5 points.
- The first player to reach 50 points wins.
- Files: time_attack.html, time_attack.css, time_attack.js
- Concept: A high-tension speed-typing arena.
- Displays a random cyberpunk sentence (from a 24-phrase terminal database).
- Correct keys glow in green; typos flash in red with a glitch effect.
- A 12-second turn timer counts down. If it hits zero, the turn fails with a score of
$0$ . -
Scoring Algorithm:
$$\text{WPM} = \frac{\text{Correct Characters} / 5}{\text{Time Elapsed in Minutes}}$$ $$\text{Score} = \text{Math.round}\left(\text{WPM} \cdot \frac{\text{Accuracy}}{100}\right)$$ - Players must maintain at least
$55%$ accuracy to score, which prevents keyboard-mashing exploits.
To provide deep transparency into the codebase, this section documents the exact algorithms and key implementation patterns used across the scripts.
The win checker in ttt.js scans for victories on dynamically sized grids. Instead of checking predefined static lines, it uses vector expansion from the coordinates
function checkWinner(row, col) {
const playerMark = board[row][col];
const directions = [
{ r: 0, c: 1 }, // Horizontal scan
{ r: 1, c: 0 }, // Vertical scan
{ r: 1, c: 1 }, // Diagonal down-right scan
{ r: 1, c: -1 } // Diagonal down-left scan
];
for (let dir of directions) {
let count = 1;
// Scan in positive vector direction
let r = row + dir.r;
let c = col + dir.c;
while (r >= 0 && r < boardSize && c >= 0 && c < boardSize && board[r][c] === playerMark) {
count++;
r += dir.r;
c += dir.c;
}
// Scan in negative vector direction
r = row - dir.r;
c = col - dir.c;
while (r >= 0 && r < boardSize && c >= 0 && c < boardSize && board[r][c] === playerMark) {
count++;
r -= dir.r;
c -= dir.c;
}
// Win threshold target is based on board scale
if (count >= winConditionTarget) {
return true;
}
}
return false;
}In dots.js, box boundaries are checked after a line is placed. The grid consists of lines between dots, where the number of boxes along each axis is
function checkAndClaimBoxes(lineType, row, col, activePlayerColor) {
let boxesClaimedThisTurn = 0;
function isBoxComplete(boxRow, boxCol) {
// A box is completed if all 4 surrounding lines are active
const topKey = `h-${boxRow}-${boxCol}`;
const bottomKey = `h-${boxRow + 1}-${boxCol}`;
const leftKey = `v-${boxRow}-${boxCol}`;
const rightKey = `v-${boxRow}-${boxCol + 1}`;
return activeLines.has(topKey) && activeLines.has(bottomKey) &&
activeLines.has(leftKey) && activeLines.has(rightKey);
}
if (lineType === 'h') {
// Check box below
if (row < boardSize && isBoxComplete(row, col)) {
claimBoxVisual(row, col, activePlayerColor);
boxesClaimedThisTurn++;
}
// Check box above
if (row > 0 && isBoxComplete(row - 1, col)) {
claimBoxVisual(row - 1, col, activePlayerColor);
boxesClaimedThisTurn++;
}
} else {
// Check box to the right
if (col < boardSize && isBoxComplete(row, col)) {
claimBoxVisual(row, col, activePlayerColor);
boxesClaimedThisTurn++;
}
// Check box to the left
if (col > 0 && isBoxComplete(row, col - 1)) {
claimBoxVisual(row, col - 1, activePlayerColor);
boxesClaimedThisTurn++;
}
}
return boxesClaimedThisTurn;
}In maze.js, a random path is generated step-by-step from the bottom row (row index
function generateSafePath() {
let path = [];
let currentRow = 5;
let currentCol = Math.floor(Math.random() * 6);
path.push({ r: currentRow, c: currentCol });
while (currentRow > 0) {
let options = [];
// Option 1: Move up
options.push({ r: currentRow - 1, c: currentCol });
// Option 2: Move left
if (currentCol > 0) {
options.push({ r: currentRow, c: currentCol - 1 });
}
// Option 3: Move right
if (currentCol < 5) {
options.push({ r: currentRow, c: currentCol + 1 });
}
// Filter options to avoid back-tracking into existing path coordinates
let validOptions = options.filter(opt => !path.some(p => p.r === opt.r && p.c === opt.c));
if (validOptions.length === 0) {
// Restart generation if grid gets blocked
return generateSafePath();
}
// Randomly select next step
let nextStep = validOptions[Math.floor(Math.random() * validOptions.length)];
path.push(nextStep);
currentRow = nextStep.r;
currentCol = nextStep.c;
}
return path;
}All game audio is synthesized dynamically in common.js by routing oscillator nodes into gain amplifiers. Below is the technical specification of the programmatically synthesized sound profiles:
The playSelect() method provides a classic sweep sweep sound utilizing frequency modulations:
playSelect() {
this.init();
if (!this.ctx) return;
const now = this.ctx.currentTime;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'triangle';
// Sweep pitch from 220Hz (A3) to 880Hz (A5) over 100ms
osc.frequency.setValueAtTime(220, now);
osc.frequency.exponentialRampToValueAtTime(880, now + 0.1);
// Decay amplitude to zero to avoid popping audio clicks
gain.gain.setValueAtTime(0.12, now);
gain.gain.exponentialRampToValueAtTime(0.001, now + 0.1);
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.start(now);
osc.stop(now + 0.1);
}This method is duplicated for each scenario with unique values:
- Keystroke (playAction): Utilizes a
squareoscillator for 80ms at 330Hz, creating a dry click sound. - Roll (playDice): Utilizes a
sawtoothoscillator with multiple random frequency adjustments triggered over 550ms, simulating a rotating cube bounce. - Victory Chords (playWin): Cycles through an array of 7 tones in a quick sequence using a
squarewave to create an 8-bit musical progression.
The visual styling uses CSS properties to manage colors across layouts. Below is a catalog of keyframes defined in the stylesheet to build the cyberpunk look:
- timerPulse: Grows the countdown timer dynamically when the player has less than 2 seconds left.
@keyframes timerPulse { from { transform: scale(1); } to { transform: scale(1.08); } }
- overlayPulse: Slowly sweeps the opacity of start buttons to draw attention.
@keyframes overlayPulse { from { opacity: 0.85; } to { opacity: 1; text-shadow: 0 0 16px var(--active-terminal-color); } }
- typoGlow: Flashes red background blocks when a typo is typed.
@keyframes typoGlow { from { background-color: rgba(255, 42, 95, 0.1); } to { background-color: rgba(255, 42, 95, 0.3); } }
This workflow diagram shows the initialization and state transitions between screens using sessionStorage:
graph TD
A[index.html: Landing Page] -->|Select Game & Players| B(sessionStorage: selectedGame, playerCount)
B --> C[setup.html: Customization Screen]
C -->|Choose Names, Avatars & Colors| D(sessionStorage: players JSON)
D --> E[Game Launcher Module]
E --> F{Select Playground}
F -->|ttt| G[ttt.html]
F -->|dots| H[dots.html]
F -->|dice| I[dice.html]
F -->|maze| J[maze.html]
F -->|reflex| K[reflex.html]
F -->|time_attack| L[time_attack.html]
This sequence diagram shows the click-to-start flow and input evaluation loops in the typing game:
sequenceDiagram
actor Player
participant UI as HTML Interface
participant Engine as time_attack.js
participant Synth as AudioSynthesizer
Player->>UI: Click Terminal Body
UI->>Engine: Trigger click zone listener
Engine->>Synth: Play select sound
Engine->>UI: Hide prompt overlay (solid background)
Engine->>UI: Focus hidden input & start countdown timer
loop Until turn completion or timeout
Player->>UI: Type key
UI->>Engine: Input listener fired
Engine->>Synth: Play keystroke sound
Engine->>UI: Highlight characters (green/red)
Engine->>UI: Calculate live WPM & Accuracy
end
Engine->>Synth: Play final feedback sound (Score/Fail)
Engine->>UI: Display stats overlay panel
Note right of Engine: Pause 3 seconds for review
Engine->>UI: Update Scoreboard & launch next player turn
TicTacToe-AI/
├── index.html # Game selection landing page
├── landing.css # Landing page style definitions
├── landing.js # User count logic and game selections
│
├── setup.html # Player registration and customization
├── setup.css # Avatar selection style grid
├── setup.js # Avatar assignments and player setups
│
├── common.css # Base styles, variables, scoreboard layouts
├── common.js # Core audio synthesizer, confetti engine
│
├── ttt.html # Tic-Tac-Toe layout
├── ttt.css # Tic-Tac-Toe grid lines
├── ttt.js # Tic-Tac-Toe search mechanics
│
├── dots.html # Dots & Boxes structure
├── dots.css # Dots layout
├── dots.js # Line check algorithms
│
├── dice.html # Dice Race page
├── dice.css # Serpentine Board tiles
├── dice.js # Dice animations and turn manager
│
├── maze.html # Maze Memory structure
├── maze.css # Flash cells animation
├── maze.js # Path memory trackers
│
├── reflex.html # Reflex Arena screen
├── reflex.css # Large reactor buttons
├── reflex.js # Reaction millisecond calculators
│
├── time_attack.html # Cyber Type Battle page
├── time_attack.css # Monospace cursor highlights
└── time_attack.js # Typing checkers and scoring engines
Because Neon Arcade is built using client-side technologies, setting it up locally is straightforward.
- Any modern web browser supporting ES6+ JavaScript, Web Audio API, and HTML5 Canvas (such as Google Chrome, Mozilla Firefox, Microsoft Edge, or Apple Safari).
- A local HTTP server is recommended to prevent CORS restrictions when running HTML files directly from the disk.
- Clone the repository:
git clone https://github.com/YourUsername/TicTacToe-AI.git
- Navigate into the directory:
cd TicTacToe-AI - Launch a local HTTP server:
- Using Python 3:
python -m http.server 8080
- Using Node.js (via
http-serverpackage):npx http-server -p 8080
- Using Python 3:
- Open the browser:
Navigate to
http://localhost:8080in your web browser.
To deploy Neon Arcade in production settings, you can use these server configurations.
Save the following as /etc/nginx/sites-available/neon-arcade:
server {
listen 80;
server_name play.neonarcade.local;
root /var/www/TicTacToe-AI;
index index.html;
# Core Security Headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self'; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; font-src https://fonts.gstatic.com; img-src 'self' data:; media-src 'self';" always;
# Cache Control for Static Assets
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 7d;
add_header Cache-Control "public, no-transform";
}
location / {
try_files $uri $uri/ =404;
}
}Create a .htaccess file at the root of the workspace directory:
# Protect files from framing attacks
Header set X-Frame-Options "DENY"
# Enable Browser Cache for static modules
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 7 days"
ExpiresByType application/javascript "access plus 7 days"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType font/woff2 "access plus 1 month"
</IfModule>
# Force UTF-8 Encoding
AddDefaultCharset UTF-8You can customize the color palette by adjusting the design tokens in common.css:
:root {
--bg-dark: #07040f;
--neon-blue: #05d9e8;
--neon-purple: #b026ff;
/* Change these hex codes to customize your arcade theme */
}You can customize the phrases in the Cyber Type Battle game by updating the PHRASES array in time_attack.js:
const PHRASES = [
"INITIALIZE DECRYPTION SECTOR ZERO BYPASSING MAIN GATEWAY NOW",
"EMERGENCY PROTOCOL DETECTED INJECTING NEURAL MALWARE SHIELD",
// Add your custom phrases here
];- Go to your repository settings on GitHub.
- In the left sidebar, click Pages.
- Under Build and deployment, select Deploy from a branch.
- Set the branch to
main(or your active branch) and path to/ (root). - Click Save. The portal will be live at
https://yourusername.github.io/repository-name/within a few minutes.
- Log in to the Cloudflare dashboard.
- Select Workers & Pages > Create application > Pages > Connect to Git.
- Select your repository.
- Keep the build settings blank (leave Build command and Build directory empty as this is a static site).
- Click Save and Deploy.
- Cause: Modern browsers block Web Audio contexts from playing sound before a user interacts with the page.
- Solution: Click anywhere on the screen (such as selecting a player color or clicking the start button) to resume the Web Audio context.
- Cause: The configuration data in
sessionStoragemight be missing if you navigate directly to a game page instead of going through the landing page. - Solution: Always start from index.html to initialize the player configurations.
- Cause: In Cyber Type Battle, the hidden input field (
#hidden-typing-input) may have lost focus. - Solution: Click inside the terminal area (
#terminal-body-click-zone) to restore focus to the input field.
| Test Case ID | Feature | Action Steps | Expected Outcome |
|---|---|---|---|
| TC-001 | Landing Redirect | Click a game card on index.html |
Saves selections and redirects to setup.html. |
| TC-002 | Avatar Conflicts | Try to select an avatar already chosen by another player | The avatar is disabled and cannot be selected. |
| TC-003 | Win Conditions | Complete a line of 3 symbols in Tic-Tac-Toe | The victory overlay appears and triggers the sound effects. |
| TC-004 | Early Clicks | Click a pad before the reactor flashes in Reflex Arena | 5 points are deducted, playing a warning tone. |
| TC-005 | Overlap Correction | Click "Initialize Override" in Type Battle | The overlay disappears immediately, revealing the phrase. |
Because Neon Arcade runs entirely in the client's browser:
- No Data Leaks: Player details, scores, and keystrokes are processed locally and never sent to a server.
- No Injection Vulnerabilities: Inputs are bound directly to UI text content using
innerTextrather thaninnerHTML, protecting the app from Cross-Site Scripting (XSS) attacks.
To maintain performance during long play sessions:
- Particles are cleared from memory when off-screen.
- Intervals and timeouts are cleared on turn transitions using
clearIntervalandclearTimeoutto prevent memory leaks.
A: You can set up local multiplayer sessions for 2 to 8 players.
A: No. Once downloaded, the application runs entirely offline.
A: Yes. However, games like Cyber Type Battle require an on-screen keyboard, so the experience is optimized for desktop and physical keyboards.
This project is licensed under the MIT License. You are free to modify, distribute, and use it in your own projects.
- Inspired by classic cyberpunk aesthetics, retro gaming systems, and tactical interfaces.
- Custom fonts provided by Google Fonts (
Orbitron,Rajdhani, andInter). - Developed as an upgraded portfolio application building upon foundations created during a web development internship at Prodigy Infotech.