@omindud/pixel-404
v1.0.0
Published
The Lost Games Library - A retro pixel-art CRT arcade widget for web 404 pages
Downloads
190
Maintainers
Readme
pixel-404 ("The Lost Games Library")
A drop-in, brand-adaptive retro pixel-art arcade widget designed specifically for web 404 error pages. Sleek Game Box frame, 12 retro theme presets, full game customization for all 8 minigames, responsive layouts (Box, Fullscreen, Compact, Borderless), transparent background inheritance, procedural Web Audio sound effects, and persistent navigation back to your main website.
Highlights & Customization Power
- 🎨 12 Curated Retro Theme Presets & Deep Custom Tokens:
- Instant 1-line themes:
'arcade-neon','cyberpunk','matrix','gameboy','dracula','synthwave','retro-amber','monochrome','nord','solarized-dark','vaporwave','minimal-light'. - Override any color token (
primaryColor,accentColor,secondaryColor,viewportBackgroundColor,borderColor,glow,crtscanlines) to match your brand down to the pixel.
- Instant 1-line themes:
- 📐 4 Layout Presentation Modes:
'box'(Default framed arcade cabinet card).'fullscreen'(Immersive retro console filling 100vw / 100vh).'compact'(Streamlined widget for sidebars, modals, or split grids).'borderless'(Clean unframed embed inheriting parent container CSS).
- 🏷️ Full 404 Page Branding & Navigation:
- Customizable error codes (
errorCode: '404'), custom titles, subtitles, and status badges (statusBadgeText: 'STATUS: 404 NOT FOUND'). - Primary "Return to Home" CTA + flexible
secondaryActions(e.g. Documentation, Status Page, Contact Support).
- Customizable error codes (
- 🕹️ Deep Customization for Every Minigame:
- Error Runner: 5 characters (
dino,mario,bot,cat,ghost), 5 environments, custom speeds, jump forces, and obstacle error labels. - Data Snake: Custom speeds, acceleration, border wall wrapping toggle, custom food & bonus labels (
'404','200'), and custom palette. - Error Breakout: Paddle width & speed, ball velocity, lives, custom brick dimensions, custom HTTP error codes (
['404', 'ERR', '500', 'FAIL']), and brick durability. - Flappy Packet: Firewall cable gaps, scroll speeds, cable widths, custom packet labels (
'404','TCP'), and stream characters. - Stack Overflow: Block dimensions, moving speeds, speed curve per layer, perfect drop tolerance, and bonus points.
- Whack-a-Bug: Session duration, spawn intervals, custom terminal key labels, custom bug types (
bug,error404,glitch,patch), and colors. - Packet Crosser: Traffic speed multipliers, lives, custom traffic lane obstacles (
DDOS,BOT,HTTP), and server destination ports (:80,:443,:8080). - Arcade Carousel: Filter allowed games, custom titles, badges, and high score toggles.
- Error Runner: 5 characters (
- 🔊 Master Volume & Procedural 8-Bit Web Audio:
- Pure native
AudioContextwith master volume control (masterVolume: 0.0to1.0) — 0 external audio asset downloads!
- Pure native
- 📱 Unified Touch Controls & Key Bindings:
- Responsive virtual D-pad and Action buttons automatically appear on mobile devices or touchscreens.
- Rebind keyboard controls to custom key sets via
controls.keyBindings.
- ⚡ Fast & Direct Single-Game Boot:
- Boot straight into any game without menus (
game: 'runner'), or choosegame: 'random'to surprise visitors with a new game on each 404 hit.
- Boot straight into any game without menus (
Installation
npm install pixel-404
# or
yarn add pixel-404
# or
pnpm add pixel-404Quickstart
1. React & Next.js (App Router)
// app/not-found.tsx
'use client';
import { PixelArcade } from 'pixel-404/react';
export default function NotFound() {
return (
<main style={{
minHeight: '100vh',
display: 'grid',
gridTemplateColumns: '1fr 1.1fr',
alignItems: 'center',
padding: '40px',
background: 'radial-gradient(circle at 20% 30%, #1e1b4b 0%, #030712 80%)',
}}>
{/* Left: Your Custom Website 404 Headline */}
<div>
<span style={{ color: '#00ffaa', fontFamily: 'monospace' }}>STATUS: 404 NOT FOUND</span>
<h1 style={{ fontSize: '72px', color: '#fff', margin: '8px 0' }}>404</h1>
<h2>Whoops! Page lost in cyberspace.</h2>
<p style={{ color: '#94a3b8', maxWidth: '420px', lineHeight: 1.6 }}>
The requested route was not found on this server. While we reboot the edge node, jump over 404 firewalls to escape!
</p>
<a href="/" style={{ color: '#00ffaa', marginTop: '16px', display: 'inline-block', fontWeight: 'bold' }}>
← Return to Main Site
</a>
</div>
{/* Right: Embedded Game Box */}
<PixelArcade
game="runner"
runner={{
character: 'dino', // 'dino' | 'mario' | 'bot' | 'cat' | 'ghost'
environment: 'retro-desert', // 'cyber' | 'retro-desert' | 'matrix' | 'space' | 'minimal'
baseSpeed: 6.5,
obstacleTexts: ['404', '500', 'TIMEOUT', 'NULL'],
}}
theme={{
preset: 'cyberpunk', // 12 retro presets available
crt: true, // Retro CRT scanlines
backgroundColor: 'transparent', // Inherits site background
}}
brand={{
showHeader: false, // Handled by your page headline
showHomeButton: false, // Handled by your page link
}}
controls={{
sound: true,
masterVolume: 0.4,
touchControls: 'auto',
}}
/>
</main>
);
}2. Plain HTML / Vanilla JavaScript
<div id="game-container" style="max-width: 680px; margin: 40px auto;"></div>
<script type="module">
import { mountPixel404 } from 'pixel-404';
const game = mountPixel404(document.getElementById('game-container'), {
game: 'snake',
snake: {
speed: 8,
wrapWalls: true,
foodLabel: '404',
bonusLabel: '200',
},
theme: {
preset: 'matrix',
crt: true,
},
brand: {
name: 'Acme Cloud',
title: 'ERROR 404',
subtitle: 'Packet lost in routing table',
homeUrl: '/',
secondaryActions: [
{ label: 'System Status', url: 'https://status.example.com', external: true },
{ label: 'Documentation', url: '/docs' },
],
},
});
// Dynamic Theme Switch at Runtime:
// game.setTheme('dracula');
// Cleanup on unmount / navigation:
// game.destroy();
</script>12 Retro Theme Presets
You can select any preset using theme.preset, or pass custom color tokens to override specific properties:
| Preset ID | Name | Primary Color | Accent Color | Aesthetic Description |
|---|---|---|---|---|
| 'arcade-neon' | Arcade Neon | #00ffaa (Neon Mint) | #ff0077 (Hot Pink) | High-contrast 80s arcade neon glow (Default) |
| 'cyberpunk' | Cyberpunk | #00f0ff (Electric Cyan) | #ffe600 (Yellow) | Night City high-tech chrome & neon |
| 'matrix' | Matrix Code | #00ff66 (Phosphor Green)| #00aa33 (Deep Green) | Digital terminal green rain |
| 'gameboy' | Game Boy Classic | #8bac0f (Light Olive) | #306230 (Forest) | Authentic 4-shade 1989 handheld LCD |
| 'dracula' | Dracula Gothic | #bd93f9 (Soft Purple) | #ff79c6 (Pink) | Sleek dark slate & pastel gothic palette |
| 'synthwave' | Synthwave Sunset | #ff71ce (Vibrant Pink) | #01cdfe (Neon Blue) | Outrun wireframe sunset aesthetics |
| 'retro-amber' | Retro Amber CRT | #ffb000 (Warm Amber) | #ff8000 (Deep Amber)| Vintage monochrome mainframe terminal |
| 'monochrome' | Monochrome Clean | #ffffff (Crisp White) | #888888 (Mid Gray) | Minimalist high-contrast monochrome |
| 'nord' | Nordic Frost | #88c0d0 (Frost Cyan) | #81a1c1 (Glacier) | Arctic ice blues and muted slate |
| 'solarized-dark' | Solarized Dark | #2aa198 (Teal) | #b58900 (Amber) | Ethan Schoonover's precision palette |
| 'vaporwave' | Vaporwave | #fca5a5 (Pastel Rose) | #38bdf8 (Sky Cyan) | Chill aesthetic nostalgic pastels |
| 'minimal-light' | Minimal Light | #2563eb (Royal Blue) | #f59e0b (Amber) | Crisp, modern light mode with clean borders |
// Example: Using a preset with custom token overrides
const config = {
theme: {
preset: 'cyberpunk',
crt: true,
borderRadius: '8px',
borderWidth: '2px',
backgroundColor: 'transparent',
}
};404 Brand & Layout Options (BrandConfig)
interface BrandConfig {
/** Layout mode: 'box' (default) | 'fullscreen' | 'compact' | 'borderless' */
layout?: 'box' | 'fullscreen' | 'compact' | 'borderless';
/** Display name of the brand or site */
name?: string;
/** URL to brand logo */
logoUrl?: string;
/** Primary 404 headline (default: '404') */
title?: string;
/** Descriptive subtitle or explanation */
subtitle?: string;
/** Error code tag (default: '404') */
errorCode?: string;
/** Custom text for status badge pill (e.g. 'STATUS: 404 NOT FOUND') */
statusBadgeText?: string;
/** Whether to show status badge (default: true) */
showStatusBadge?: boolean;
/** Destination for Return Home CTA (default: '/') */
homeUrl?: string;
/** Text for Return Home CTA (default: 'Return to Main Site') */
homeText?: string;
/** Additional secondary links (Documentation, Status, Contact) */
secondaryActions?: Array<{
label: string;
url: string;
external?: boolean;
onClick?: () => void;
}>;
/** Render brand header inside the game box (default: true) */
showHeader?: boolean;
/** Render return home button inside the game box (default: true) */
showHomeButton?: boolean;
/** Screen aspect ratio (default: '4/3', e.g. '16/9', 'auto') */
aspectRatio?: string;
/** Max width of widget (default: '680px') */
maxWidth?: string;
}Minigame Configuration Reference
1. Error Runner (RunnerConfig)
runner: {
character: 'dino', // 'dino' | 'mario' | 'bot' | 'cat' | 'ghost'
environment: 'cyber', // 'cyber' | 'retro-desert' | 'matrix' | 'space' | 'minimal'
baseSpeed: 6.0, // Initial scrolling speed
jumpForce: -440, // Upward velocity on jump
gravity: 1200, // Gravitational pull
groundColor: '#00ffaa', // Custom ground track color
obstacleTexts: ['404', 'NULL'], // Custom text labels on ground blocks & drones
playerSpriteUrl: 'https://...', // Optional custom mascot image
gameOverTitle: 'SYSTEM CRASH', // Custom Game Over headline
}2. Data Snake (SnakeConfig)
snake: {
speed: 7, // Starting movements per second
speedIncrease: 0.002, // Acceleration per food consumed
wrapWalls: true, // Wrap edges instead of crashing on wall hit
foodLabel: '404', // Text label on standard food items
bonusLabel: '200', // Text label on bonus items
snakeColor: '#00ffaa', // Body segments color
snakeHeadColor: '#ffffff', // Snake head color
foodColor: '#ff0077', // Food color
bonusColor: '#f59e0b', // Bonus item color
gridSize: { cols: 24, rows: 16 }, // Grid dimensions
gameOverTitle: 'BUFFER OVERFLOW', // Custom Game Over title
}3. Error Breakout (BreakoutConfig)
breakout: {
ballSpeed: 220, // Ball velocity (pixels/sec)
ballSize: 6, // Ball diameter
ballColor: '#ffffff', // Ball color
paddleWidth: 56, // Paddle width in logical pixels
paddleSpeed: 320, // Paddle keyboard speed
lives: 3, // Starting lives
brickRows: 4, // Number of brick rows
brickCols: 7, // Number of columns
brickTexts: ['404', 'ERR', '500'], // Labels cycled through bricks
brickColors: ['#ef4444', '#f59e0b'],// Palette for rows
brickHealth: 2, // Max hit points per brick
gameOverTitle: 'FIREWALL BREACH', // Custom Game Over title
}4. Flappy Packet (FlappyConfig)
flappy: {
gravity: 740, // Downward gravity
flapStrength: -250, // Upward lift velocity per tap/space
cableGap: 84, // Vertical gap between top and bottom cables
cableSpeed: 125, // Horizontal scroll speed
cableWidth: 42, // Cable pillar width
spawnInterval: 1.65, // Interval between cable pairs (seconds)
packetLabel: '404', // Label on winged packet
cableColor: '#ff0077', // Cable color
packetColor: '#00ffaa', // Packet color
backgroundChars: ['0', '1', 'TCP'], // Binary background stream
gameOverTitle: 'CONNECTION LOST', // Custom Game Over title
}5. Stack Overflow (StackerConfig)
stacker: {
blockWidth: 120, // Starting block width
blockHeight: 18, // Block layer height
initialSpeed: 3.0, // Starting horizontal swing speed
speedIncreasePerLayer: 0.15, // Speedup per stacked block
perfectTolerance: 5, // Pixel margin considered a "Perfect Drop"
blockLabel: 'STACK', // Label text on blocks
blockColors: ['#38bdf8', '#818cf8'],// Colors cycled per layer
bonusPoints: 25, // Extra points for perfect alignment
gameOverTitle: 'STACK OVERFLOW', // Custom Game Over title
}6. Whack-a-Bug (WhackConfig)
whack: {
gameDuration: 30, // Session timer countdown in seconds
spawnCooldown: 0.6, // Time between bug emergences
minSpawnCooldown: 0.25, // Minimum spawn interval in frenzy mode
keyLabels: ['1','2','3','4','5','6','7','8','9'], // Custom slot hotkey labels
bugTexts: {
bug: 'BUG', // Normal bug label
error404: '404', // 404 error target label
glitch: 'ERR', // Glitch target label
patch: 'FIX', // Patch bonus target label
},
bugColor: '#ef4444', // Standard bug color
glitchColor: '#a855f7', // Glitch target color
patchColor: '#22c55e', // Patch target color
gameOverTitle: 'SESSION TIMEOUT', // Custom Game Over title
}7. Packet Crosser (CrosserConfig)
crosser: {
lives: 3, // Player packet lives
speedMultiplier: 1.0, // Obstacle speed multiplier
trafficLabels: {
trucks: ['DDOS', 'BOT', 'HTTP'], // Lane labels
lasers: ['ERR', 'CORRUPT'],
},
portLabels: [':80 HTTP', ':443 SSL', ':8080 API'], // Destination dock labels
playerColor: '#00ffaa', // Player packet color
gameOverTitle: 'PACKET CORRUPTED', // Custom Game Over title
}8. Arcade Carousel (MenuConfig)
menu: {
allowedGames: ['runner', 'snake', 'breakout'], // Filter selectable games
menuTitle: 'THE LOST ARCADE', // Header title
showHighScores: true, // Show high score medals
}Audio & Controls (ControlsConfig)
controls: {
sound: true, // Enable Web Audio procedural sound effects
masterVolume: 0.5, // Volume: 0.0 (silent) to 1.0 (full)
showSoundToggle: true, // Show on-screen 🔊/🔇 button
showRestartButton: true, // Show on-screen ↺ button
touchControls: 'auto', // 'auto' | 'always' | 'never' (Mobile D-pad & Actions)
keyBindings: { // Rebind keyboard controls
jump: ['Space', 'ArrowUp', 'KeyW'],
duck: ['ArrowDown', 'KeyS'],
left: ['ArrowLeft', 'KeyA'],
right: ['ArrowRight', 'KeyD'],
},
}Runtime Imperative API
Both Vanilla JS and React expose programmatic controls:
Vanilla JavaScript (Pixel404Instance)
const game = mountPixel404(mountEl, config);
// Change theme preset or tokens dynamically without reloading:
game.setTheme('dracula');
game.setTheme({ primaryColor: '#ff0055', crt: true });
// Update game configuration:
game.updateConfig({
game: 'breakout',
controls: { masterVolume: 0.2 },
});
// Restart active game:
game.restart();
// Clean up listeners, timers, and canvas contexts:
game.destroy();React (PixelArcadeRef)
import { useRef } from 'react';
import { PixelArcade, PixelArcadeRef } from 'pixel-404/react';
export function ArcadeComponent() {
const arcadeRef = useRef<PixelArcadeRef>(null);
const switchTheme = () => {
arcadeRef.current?.setTheme('cyberpunk');
};
return (
<div>
<button onClick={switchTheme}>Cyberpunk Mode</button>
<PixelArcade ref={arcadeRef} game="runner" />
</div>
);
}Demos
Run the local interactive customization playground:
npm run dev- Interactive Customizer Hub:
http://localhost:5173/(Test all 12 presets, 4 layout modes, 8 games, and generate live drop-in code) - Standalone Runner:
http://localhost:5173/runner.html - Standalone Snake:
http://localhost:5173/snake.html - Standalone Breakout:
http://localhost:5173/breakout.html - Standalone Flappy:
http://localhost:5173/flappy.html - Standalone Stacker:
http://localhost:5173/stacker.html - Standalone Whack:
http://localhost:5173/whack.html - Standalone Crosser:
http://localhost:5173/crosser.html
License
MIT © Contributors
