PLUR
Peace, Love, Unity, Roll — momentum-based 3D soccer-ball racer with a global leaderboard.
PLUR is a momentum-based 3D browser game where you roll a procedurally-textured soccer ball around a stadium, collecting coins and country flags, dodging hazards, and scoring goals. Three.js + WebGL on the client, vanilla PHP + SQLite serving the web portal and a global leaderboard, glassmorphism on the chrome. No framework on the front — just HTML5/CSS3/JS — and a CI/CD pipeline scaffolded for a future native C/OpenGL Windows build.
- JavaScript
- Three.js
- WebGL
- PHP
- SQLite
- Apache
- Lucide
PLUR — Peace, Love, Unity, Roll — is a momentum-based 3D browser game where the player rolls a procedurally-textured soccer ball around a stadium, collecting coins and country flags, dodging hazards, and scoring goals. The game is rendered in Three.js / WebGL; the portal around it (landing page, leaderboard, download page, admin) is hand-rolled HTML5/CSS3/vanilla JS with a glassmorphism skin.
What makes the rolling feel right
- Real momentum, not arcade physics — the ball decelerates on flat ground, accelerates down ramps, and carries energy through corners. Players who lean into line-choice are rewarded; players who mash forward stall out on the slow stuff.
- Procedural ball texturing so every coin and flag pickup actually changes the look of the thing you're steering. The ball is the playable surface, not just a sprite.
- Stadium environment with hazards that
respect the ball's mass — bumpers shove, ramps redirect,
goal frames let you score from clever angles. The mesh
catalogue is in
stadium_meshes.json; new levels are JSON edits, not engine changes. - Coin + flag collection drives the score; a global leaderboard at /scores.html keeps the run honest.
How it's hosted
Static front-end out of public/ on Apache. PHP +
SQLite under the API in api/ for score submission,
leaderboard retrieval, asset management, and admin auth — REST-
ish endpoints, no framework. The whole stack runs on the same
box as the rest of the Gaming World installations; deploys are
rsync-and-reload. CI/CD is scaffolded for a future native
Windows port (cross-compiled C/OpenGL) but the browser build is
the primary surface today.
The naming
"Peace, Love, Unity, Respect" is the original PLUR — the rave-culture credo. Swapping Respect for Roll was a one-letter joke that committed itself the first time someone said it out loud. The whole project has the same register: serious physics under a name that's clearly not serious.
Straight from the source
The project's own README.
Rendered in place — every link, image, and code block carried over from the repo. The page below is what a contributor would see opening the project for the first time.
PLUR - Peace, Love, Unity, Roll
A momentum-based 3D soccer ball racing game built with Three.js, served through a vanilla PHP/SQLite web portal with a global leaderboard. Live at PLUR.GamingWorld.uk.
Table of Contents
- Overview
- Live Demo
- Screenshots
- Technology Stack
- Project Structure
- Game Engine Architecture
- Web Portal
- Backend API
- Database
- Getting Started
- Task Runner (justfile)
- Deployment
- Configuration
- Security
- File Types Reference
- Roadmap
- Contributing
- License
Overview
PLUR is a full-stack gaming platform consisting of:
A 3D browser game - A soccer ball racer inside a 3D stadium environment, built entirely in JavaScript with Three.js (WebGL). Players roll a procedurally-textured soccer ball around a stadium, collecting coins and country flags, dodging hazards, and scoring goals.
A web portal - A responsive, glass-morphism-styled landing page with a leaderboard, download page, and admin panel. No frameworks - pure HTML5, CSS3, and vanilla JavaScript.
A PHP/SQLite backend - REST-like API endpoints for score submission, leaderboard retrieval, asset management, and admin authentication.
CI/CD pipeline - GitHub Actions workflow (placeholder) for future cross-compilation of a native C/OpenGL Windows executable.
Current version: See CHANGELOG.md for the latest release.
Live Demo
Play the game in your browser: https://PLUR.GamingWorld.uk/game/
View the leaderboard: https://PLUR.GamingWorld.uk/scores.html
Technology Stack
Frontend (Web Portal)
| Technology | Purpose |
|---|---|
| HTML5 | Semantic markup, Web Manifest, SEO meta tags |
| CSS3 (vanilla) | 15 modular stylesheets, glass morphism design system, CSS custom properties, clamp() responsive sizing, @import composition |
| JavaScript (vanilla ES6) | Scroll animations (IntersectionObserver), theme toggle, parallax effects |
| Google Fonts | Orbitron (headings), Space Grotesk (subheadings), Inter (body) |
| Lucide Icons | 1703-symbol SVG sprite (lucide-sprite.svg) |
| WebP | All images optimized in WebP format |
Game Engine
| Technology | Purpose |
|---|---|
| JavaScript ES6 Modules | 13-module game engine, no build step, runs natively in browser |
| Three.js v0.162.0 | WebGL 3D rendering (loaded via importmap from unpkg CDN) |
| GLTFLoader + DRACOLoader | Loads Draco-compressed .glb 3D stadium model |
| Canvas API | Procedural texture generation (soccer ball pentagons, coin star emblem) |
| Web Audio API | Sound effects (coin collect, jump, death, victory) |
| Touch Events API | Mobile virtual joystick and jump button |
| requestAnimationFrame | 60 FPS game loop with delta-time physics |
| localStorage | Dev tuner settings persistence |
Backend
| Technology | Purpose |
|---|---|
| PHP 8.1 | API endpoints, session management, file uploads |
| SQLite 3 | Database (WAL mode, foreign keys, PDO) |
| PDO | Prepared statements for all database queries |
Infrastructure
| Technology | Purpose |
|---|---|
| Ubuntu Linux | Server OS |
| Apache 2.4 | Web server with mod_rewrite, mod_deflate, mod_headers |
| Let's Encrypt | SSL/TLS via certbot (auto-renewal) |
| Hetzner | VPS/dedicated hosting |
| Git | Version control |
| GitHub | Repository hosting (private: saintpetejackboy/PLUR) |
| GitHub Actions | CI/CD pipeline |
| just | Task runner (justfile) |
Build Tools (npm)
| Package | Purpose |
|---|---|
@gltf-transform/core |
GLB/GLTF 3D model manipulation |
@gltf-transform/extensions |
GLTF extension support |
@gltf-transform/functions |
GLTF optimization functions |
draco3dgltf |
Draco 3D mesh compression |
gltf-pipeline |
GLB optimization pipeline |
obj2gltf |
OBJ to GLTF/GLB conversion |
lucide-static |
Icon library source |
sharp |
Image processing and optimization |
Project Structure
/var/www/plur/
├── public/ # Apache document root
│ ├── index.html # Landing page
│ ├── scores.html # Leaderboard page
│ ├── download.html # Download page
│ ├── game/ # Game client
│ │ ├── index.html # Game launcher (importmap, HUD, menus, dev tuner)
│ │ ├── js/ # Game JS modules (synced from game_src/js/)
│ │ └── css/
│ │ └── game.css # Game-specific styles
│ ├── admin/ # Admin dashboard
│ │ ├── index.html
│ │ └── admin.css
│ ├── css/ # Portal stylesheets (15 modular files)
│ │ ├── theme.css # Main entry point (@import chain)
│ │ ├── variables.css # CSS custom properties
│ │ ├── reset.css # CSS reset
│ │ ├── layout.css # Grid/flex layout
│ │ ├── typography.css # Font faces, sizing
│ │ ├── buttons.css # 3D button styles
│ │ ├── cards.css # Glass morphism cards
│ │ ├── forms.css # Custom inputs, toggles
│ │ ├── animations.css # Keyframe animations
│ │ ├── header.css # Site header/nav
│ │ ├── hero.css # Hero section
│ │ ├── footer.css # Site footer
│ │ ├── modal.css # Modal overlays
│ │ ├── tables.css # Leaderboard tables
│ │ ├── scrollbars.css # Custom scrollbar styling
│ │ ├── pages.css # Page-specific overrides
│ │ ├── responsive.css # Media queries
│ │ └── download.css # Download page styles
│ ├── js/ # Portal scripts
│ │ ├── theme-toggle.js # Dark/light mode
│ │ ├── scroll-animations.js # IntersectionObserver fades
│ │ ├── scores.js # Leaderboard fetching
│ │ ├── download.js # Download verification
│ │ └── admin.js # Admin panel logic
│ ├── assets/
│ │ ├── images/ # WebP images (~15 files)
│ │ ├── icons/ # Lucide SVG sprite
│ │ ├── models/ # 3D models
│ │ │ └── stadium.glb # Draco-compressed stadium (8.6 MB)
│ │ └── game/ # Game-specific assets
│ ├── downloads/ # Distributable game packages
│ ├── .htaccess # Rewrites, security headers, gzip
│ ├── robots.txt
│ ├── humans.txt
│ ├── sitemap.xml
│ └── site.webmanifest
│
├── game_src/ # Game source code (canonical)
│ └── js/ # 13 ES6 modules (~3,700 LOC)
│ ├── main.js # Game loop, state machine, score submission
│ ├── ball.js # Player ball physics, boost, procedural texture
│ ├── physics.js # Gravity, friction, AABB collision detection
│ ├── renderer.js # Three.js WebGL setup, lights, shadows
│ ├── camera.js # Smooth-follow camera
│ ├── controls.js # Keyboard + touch input, vehicle-style steering
│ ├── level.js # Stadium GLB loading, collision proxies, goals
│ ├── collectibles.js # Coins, flags, collection mechanics
│ ├── hazards.js # Crushers, spikes, death zones, bumpers
│ ├── hud.js # Score, timer, lives, speed/boost meters
│ ├── audio.js # Web Audio API sound effects
│ ├── particles.js # Sparkle, explosion, trail particle systems
│ └── scoreboard.js # Leaderboard UI, on-screen keyboard
│
├── api/ # PHP backend
│ ├── config.php # Environment loader
│ ├── database.php # PDO + SQLite connection
│ ├── scores.php # GET /api/scores.php - leaderboard
│ ├── submit-score.php # POST /api/submit-score.php - score submission
│ ├── verify-download.php # POST /api/verify-download.php - download auth
│ ├── .htaccess # API security rules
│ └── admin/
│ ├── auth.php # Admin session management
│ ├── verify.php # Session verification
│ ├── helpers.php # Utility functions
│ ├── assets.php # Asset upload/management
│ └── stats.php # Game statistics
│
├── database/ # SQLite storage
│ ├── plur.db # Main database (not committed)
│ ├── init.php # Schema initializer
│ └── backups/ # Timestamped backups (not committed)
│
├── docs/ # Documentation
│ ├── quick-start.md # Project brief and phase overview
│ ├── stack.md # Technology overview
│ ├── post-work.md # AI agent checklist
│ └── original-idea.md # Original concept notes
│
├── tools/
│ └── extract-stadium-colliders.mjs # GLB mesh collision extractor
│
├── .github/
│ └── workflows/
│ └── windows-build.yml # GitHub Actions (placeholder for C/OpenGL build)
│
├── justfile # Task runner commands
├── package.json # npm dependencies
├── CHANGELOG.md # Version history (Keep a Changelog format)
├── ROADMAP.md # Feature roadmap
├── .env # Runtime config (not committed)
└── .gitignore # Excludes secrets, databases, binaries, node_modules
Game Engine Architecture
The game engine is a custom 13-module JavaScript system with no build step. Modules communicate through ES6 imports/exports and a shared window namespace for the dev tuner.
Module Dependency Graph
main.js (entry point - game loop & state machine)
├── renderer.js → Three.js scene, WebGL renderer, lights, shadows
├── camera.js → Smooth-follow camera with configurable offset
├── controls.js → Keyboard (WASD/Arrows/Space) + touch joystick input
├── ball.js → Player sphere, physics body, procedural soccer texture
│ └── physics.js → Gravity, drag, bounce, AABB collision detection
├── level.js → Stadium GLB loader, collision proxy builder, goal zones
├── collectibles.js → Coin/flag placement, collection logic, scoring
├── hazards.js → Crushers, spikes, bumpers, death zones
├── hud.js → DOM-based HUD (score, timer, lives, speed meter)
├── audio.js → Web Audio API oscillator-based sound effects
├── particles.js → GPU-friendly particle systems (sparkle, explosion, trail)
└── scoreboard.js → End-game UI, on-screen keyboard, leaderboard display
How the Game Renders in the Browser
Loading:
public/game/index.htmlloads Three.js via an ES6importmappointing to the unpkg CDN. Game modules are loaded as<script type="module">tags with cache-bust query strings.Initialization:
main.jscreates the Three.js scene, renderer (WebGL with PCF soft shadows, ACES filmic tone mapping), and camera. The stadium.glbmodel is loaded viaGLTFLoaderwithDRACOLoaderfor mesh decompression.Game Loop: A
requestAnimationFrameloop runs at 60 FPS with delta-time (dt) passed to all systems:controls.update()- Read input stateball.update(dt)- Apply forces, integrate velocityphysics.resolveCollisions()- AABB collision against stadium proxiescollectibles.update(dt)- Animate coins/flags, check collectionhazards.update(dt)- Animate hazards, check death collisionsparticles.update(dt)- Update particle systemscamera.update(dt)- Smooth-follow the ballhud.update()- Refresh DOM HUD elementsrenderer.render()- Draw frame
Rendering: Three.js renders the scene with:
- Directional light with 4096x4096 shadow map
- Ambient + fill lights
- Fog for depth
- Procedural textures (soccer ball via icosahedron math, coins via canvas radial gradients)
Input: Vehicle-style steering where A/D rotate the ball's heading and W/S thrust along it. Space jumps. Mobile uses a virtual joystick (left thumb) and jump button (right thumb).
Scoring: When the ball enters a goal zone, the game ends. An on-screen keyboard lets the player enter their name. The score is POSTed to
/api/submit-score.phpand the leaderboard refreshes.
Dev Tuner
Press \ (backslash) in-game to open the Dev Tuner panel. It provides real-time sliders for:
- Stadium position, scale, rotation
- Ball radius, move force, jump force, max speed
- Physics: gravity, ground drag, air drag, bounce
- Toggles: God Mode, Debug XYZ coordinates
Settings persist to localStorage.
Web Portal
The portal is a multi-page static site with no JavaScript framework:
| Page | URL | Description |
|---|---|---|
| Landing | / |
Hero with image-based CTAs, feature cards with parallax, glass morphism design |
| Game | /game/ |
Full-screen 3D game client |
| Scores | /scores.html |
Global leaderboard with sortable table |
| Download | /download.html |
Game download page (password-protected) |
| Admin | /admin/ |
Dashboard for asset management and statistics |
Design System
- Glass morphism:
backdrop-filter: blur()with semi-transparent backgrounds - CSS custom properties: All colors, fonts, spacing defined in
variables.css - Responsive:
clamp()font sizing, mobile-first media queries - Animations:
IntersectionObserver-triggered fade-ins, parallax scrolling - Dark/Light mode: Toggle with
localStoragepersistence - No CSS framework: All styles are hand-written, modular CSS
Backend API
All endpoints are vanilla PHP with PDO prepared statements.
| Endpoint | Method | Description |
|---|---|---|
/api/scores.php |
GET |
Fetch top 100 leaderboard entries (JSON) |
/api/submit-score.php |
POST |
Submit a score {player_name, score, time_survived, flags_collected} |
/api/verify-download.php |
POST |
Verify download password |
/api/admin/auth.php |
POST |
Admin login (creates session token) |
/api/admin/verify.php |
POST |
Verify admin session token |
/api/admin/stats.php |
GET |
Game statistics (total scores, unique players) |
/api/admin/assets.php |
POST/GET |
Upload and manage game assets |
Database
Engine: SQLite 3 with WAL mode and foreign keys enabled.
Location: database/plur.db (not committed to git)
Schema
CREATE TABLE highscores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_name TEXT NOT NULL,
score INTEGER DEFAULT 0,
time_survived REAL DEFAULT 0.0,
flags_collected TEXT DEFAULT '[]',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE admin_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
token TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME NOT NULL
);
CREATE TABLE game_assets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL,
original_name TEXT,
category TEXT,
description TEXT,
tags TEXT DEFAULT '[]',
file_size INTEGER,
mime_type TEXT,
uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
active INTEGER DEFAULT 1
);
Initialize
just init-db
# or
php database/init.php
Backup
just db-backup
# Creates: database/backups/plur_YYYYMMDD_HHMMSS.db
Getting Started
Prerequisites
- Ubuntu/Debian Linux (or similar)
- Apache 2.4 with
mod_rewrite,mod_deflate,mod_headers - PHP 8.1+ with
pdo_sqliteextension - Node.js 18+ and npm (for build tools only)
- just task runner (installation)
- Git
Installation
# 1. Clone the repository
git clone [email protected]:saintpetejackboy/PLUR.git /var/www/plur
cd /var/www/plur
# 2. Install npm dependencies (build tools only, not needed for runtime)
npm install
# 3. Create environment configuration
cp .env.example .env
# Edit .env with your passwords and paths
# 4. Initialize the database
just init-db
# 5. Configure Apache VirtualHost
# Point DocumentRoot to /var/www/plur/public/
# Enable mod_rewrite
# 6. Set permissions
sudo chown -R www-data:www-data public/ database/
# 7. Set up SSL
sudo certbot --apache -d your-domain.com
# 8. Start Apache
just serve
Syncing Game Files
Game source lives in game_src/js/. After editing, sync to the public directory:
cp game_src/js/*.js public/game/js/
# Remember to update cache-bust versions (?v=0XX) in public/game/index.html
Task Runner (justfile)
All project operations use just (a modern make alternative).
just # List all available commands
just serve # Restart Apache
just deploy # Build + set permissions + restart Apache
just status # Git status, current version, Apache status
just logs # Tail Apache error logs (last 50 lines)
just push "message" # Git add, commit, push to origin/main
just release 0.3.0 # Tag release, update CHANGELOG, push with tag
just bump-patch # Auto-increment patch version (0.2.5 -> 0.2.6)
just bump-minor # Auto-increment minor version (0.2.5 -> 0.3.0)
just db-backup # Backup SQLite with timestamp
just init-db # Initialize/reset database schema
just check-ssl # Verify Let's Encrypt certificate status
just clean-old-downloads # Remove old ZIPs, keep latest
just build-game # Placeholder (future C/OpenGL compilation)
Deployment
The project deploys via git push to a Hetzner server:
# Full deploy cycle
just deploy
# Or manually:
just build-game # Build (placeholder)
sudo chown -R www-data:www-data public/ database/ # Permissions
just serve # Restart Apache
Release Process
# 1. Update CHANGELOG.md with changes
# 2. Run the release command
just release 0.3.0
# This will: update .env version, insert CHANGELOG header, commit, tag, push
Server Architecture
Browser ──HTTPS──▶ Apache 2.4 ──▶ public/ (static HTML/CSS/JS/assets)
──▶ public/game/ (Three.js game client)
──▶ api/*.php (PHP endpoints)
──▶ database/plur.db (SQLite via PDO)
Configuration
Environment Variables (.env)
DOWNLOAD_PASSWORD=<password for download page>
ADMIN_PASSWORD=<password for admin panel>
DB_PATH=/var/www/plur/database/plur.db
SITE_URL=https://PLUR.GamingWorld.uk
APP_VERSION=0.2.5
Three.js CDN (importmap)
Three.js is loaded from unpkg CDN via an importmap in public/game/index.html:
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
}
No local Three.js installation is needed for runtime.
Cache Busting
All CSS and JS files use query-string cache busting (?v=0XX). Increment the version number after changes to ensure browsers load the latest files.
Security
- HTTPS only - All HTTP redirected to HTTPS via Apache
- Prepared statements - All database queries use PDO prepared statements
- Input sanitization -
htmlspecialchars()on all user output .envexcluded - Secrets never committed to git.gitblocked - Apache.htaccessblocks access to.git/- Database blocked -
.db,.sql,.bakfiles blocked via.htaccess - Security headers -
X-Frame-Options,X-Content-Type-Options,Content-Security-Policy - CORS configured - Appropriate headers on API endpoints
- Session tokens - Admin sessions use random tokens with expiration
File Types Reference
This table covers every file type in the project, useful for AI tools and code analysis:
| Extension | Language/Format | Count | Location | Purpose |
|---|---|---|---|---|
.html |
HTML5 | 5 | public/, public/game/, public/admin/ |
Web pages and game launcher |
.css |
CSS3 | ~17 | public/css/, public/game/css/, public/admin/ |
Styling (modular, no framework) |
.js |
JavaScript ES6 | ~25 | game_src/js/, public/js/, tools/ |
Game engine, portal scripts, build tools |
.php |
PHP 8.1 | 8 | api/, database/ |
Backend API and database |
.webp |
WebP image | ~15 | public/assets/images/ |
Optimized images |
.svg |
SVG | 1 | public/assets/icons/ |
Lucide icon sprite (1703 icons) |
.glb |
glTF Binary | 1 | public/assets/models/ |
3D stadium model (Draco-compressed) |
.json |
JSON | 3 | root, game_src/ |
npm configs, web manifest |
.md |
Markdown | 5+ | root, docs/ |
Documentation |
.yml |
YAML | 1 | .github/workflows/ |
CI/CD pipeline |
.xml |
XML | 1 | public/ |
Sitemap |
.txt |
Plain text | 2 | public/ |
robots.txt, humans.txt |
.db |
SQLite 3 | 1 | database/ |
Application database |
.mjs |
ES Module JS | 1 | tools/ |
Node.js build script |
.ico / .png |
Favicon | 4 | public/ |
Browser icons |
Roadmap
Completed
- Phase 1 (v0.1.x): Infrastructure - Apache/SSL, landing page, SQLite, leaderboard API, download system, justfile, CI/CD, SEO, glass morphism design
- Phase 2 (v0.2.x): Game Development - Three.js engine, procedural soccer ball, stadium environment, coins/flags, hazards, on-screen keyboard, leaderboard integration, touch controls, tuned physics, audio, particles
In Progress
- Tutorial zone / guided first platform
- Coin/flag variety and placement improvements
- Moving platform refinements
Planned - Phase 3 (v0.3.x): Polish
- Multiple levels/stages
- Randomized elements for replayability
- Power-up mechanics (double-jump, etc.)
- Advanced hazards (wind zones, magnets, teleporters)
- Background music / ambient audio
- Performance optimization (LOD, culling)
Planned - Phase 4 (v1.0.0): Launch
- Full asset integration
- Public beta testing
- Leaderboard seasons (weekly resets)
- Admin panel enhancements
- Marketing page updates
- Cross-platform downloadable builds (see below)
Download Distribution Roadmap
The game currently runs in-browser only. The roadmap for downloadable versions:
Web export (near-term): Package the browser game as a standalone HTML bundle (single-file or zip) that runs offline without a server.
Electron wrapper (mid-term): Wrap the Three.js game in Electron for Windows/macOS/Linux desktop apps with:
- Offline play
- Native window chrome
- Auto-updater
- Local score caching with sync-on-connect
Native C/OpenGL build (long-term): The original vision - a Neverball-inspired C/OpenGL engine cross-compiled to Windows
.exevia MinGW in GitHub Actions. The CI/CD workflow (.github/workflows/windows-build.yml) is already scaffolded as a placeholder.Mobile (future): PWA-first approach (the
site.webmanifestis already in place), potentially followed by Capacitor/Cordova wrapping for app store distribution.
Contributing
This is a private project by GamingWorld.uk. Contact the repository owner for contribution guidelines.
License
All rights reserved. See repository for licensing details.
Build something like this
Want a tool like this for your shop?
We've shipped this kind of thing before. Twenty-minute intro call, no slides.