{"_id":"@3rg0n/breakout404-core","_rev":"3-f1890cfc2143d588188312134c966b49","name":"@3rg0n/breakout404-core","dist-tags":{"latest":"0.6.1"},"versions":{"0.5.0":{"name":"@3rg0n/breakout404-core","version":"0.5.0","keywords":["404","breakout","game","canvas"],"license":"MIT","_id":"@3rg0n/breakout404-core@0.5.0","maintainers":[{"name":"3rg0n","email":"ergoncopeland@hotmail.com"}],"dist":{"shasum":"6ff2664d3fddc8d37a886b599ea6cc5a4717423d","tarball":"https://registry.npmjs.org/@3rg0n/breakout404-core/-/breakout404-core-0.5.0.tgz","fileCount":13,"integrity":"sha512-0KwiJ9BWECIgRVi8Z6i6e5AF9oYvchpwDbrhw064NWFkFEDP5bjlcu20N51z+HITpZLAjY0nz4c2h8D/8uh70g==","signatures":[{"sig":"MEQCICD+Pz4fLCgrJbbeJ5b7BxewtXt8Tf4ytDoBK/cmZWYPAiBRItJu3CDyk3okNrzZ4fOIdG7Jvz2/OQ8QAta+jg6QUw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":22116},"main":"./dist/breakout404.umd.js","types":"./dist/index.d.ts","module":"./dist/breakout404.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/breakout404.mjs","require":"./dist/breakout404.umd.js"}},"gitHead":"3dfd6ff4076b175a279e2bd4dde4b2fe44356ca6","scripts":{"dev":"vite build --watch","build":"vite build && tsc --emitDeclarationOnly","clean":"rimraf dist"},"_npmUser":{"name":"3rg0n","email":"ergoncopeland@hotmail.com"},"_npmVersion":"11.6.2","description":"Core Breakout404 game engine - a Breakout-style 404 page game","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.6","rimraf":"^5.0.10","typescript":"^5.9.3","vite-plugin-dts":"^4.5.4"},"_npmOperationalInternal":{"tmp":"tmp/breakout404-core_0.5.0_1775681177634_0.7101672514584394","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@3rg0n/breakout404-core","version":"0.6.0","keywords":["404","breakout","game","canvas"],"license":"MIT","_id":"@3rg0n/breakout404-core@0.6.0","maintainers":[{"name":"3rg0n","email":"ergoncopeland@hotmail.com"}],"dist":{"shasum":"d2fa640d582e71914b81a5e25684f2bf3ecd6c6e","tarball":"https://registry.npmjs.org/@3rg0n/breakout404-core/-/breakout404-core-0.6.0.tgz","fileCount":16,"integrity":"sha512-O9CWgKycjsVyXPG2AWaJXDCh2zwUqYlfFp/qMt5YeRJzFphJvTSolhpgivxcqu6VgBbpCBoPrNkqpGXlb5Lmrg==","signatures":[{"sig":"MEUCIQCEC7HmO/LO2aXrBdSPvH2bps7U2HNl7VZ8h+G3XqWJZQIgVTYPN+2uQDNYq03234gtQnX8yCwtCqmR9taLZEx2uEk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33354},"main":"./dist/breakout404.umd.js","types":"./dist/index.d.ts","module":"./dist/breakout404.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/breakout404.mjs","require":"./dist/breakout404.umd.js"}},"scripts":{"dev":"vite build --watch","build":"vite build && tsc --emitDeclarationOnly","clean":"rimraf dist"},"_npmUser":{"name":"3rg0n","email":"ergoncopeland@hotmail.com"},"description":"Core Breakout404 game engine - a Breakout-style 404 page game","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^8.2.1","rimraf":"^5.0.10","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/breakout404-core_0.6.0_1788378557477_0.22721454597383306","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"@3rg0n/breakout404-core","version":"0.6.1","description":"Core Breakout404 game engine - a Breakout-style 404 page game","main":"./dist/breakout404.umd.js","module":"./dist/breakout404.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/breakout404.mjs","require":"./dist/breakout404.umd.js"}},"keywords":["404","breakout","game","canvas"],"license":"MIT","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"devDependencies":{"rimraf":"^5.0.10","typescript":"^5.9.3","vite":"^8.2.1"},"scripts":{"build":"vite build && tsc --emitDeclarationOnly","dev":"vite build --watch","clean":"rimraf dist"},"_nodeVersion":"26.0.0","_id":"@3rg0n/breakout404-core@0.6.1","dist":{"integrity":"sha512-PN9TgJR1uj9LifDlyM+KqKZ/q+/9+S2I8aJGGwnVE55WsMtDhz2dIRC+1Tc3f/U0PL0Y8stuzE7EQlHeyCfHEg==","shasum":"576cf679361ff17526379bc85919f0bf75fbc50c","tarball":"https://registry.npmjs.org/@3rg0n/breakout404-core/-/breakout404-core-0.6.1.tgz","fileCount":13,"unpackedSize":37721,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCvebb6tgJrNZr/LWwfsPHgRhpTMES8anGr31lmXKn5DgIhAI1Q98koUbB2KRGQrZHU6BpkwpFBHrBVzILSqAFVOyPn"}]},"_npmUser":{"name":"3rg0n","email":"ergoncopeland@hotmail.com"},"directories":{},"maintainers":[{"name":"3rg0n","email":"ergoncopeland@hotmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/breakout404-core_0.6.1_1788440255871_0.38355488015111194"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-08T20:46:17.463Z","modified":"2026-09-03T12:57:36.342Z","0.5.0":"2026-04-08T20:46:17.774Z","0.6.0":"2026-09-02T19:49:17.618Z","0.6.1":"2026-09-03T12:57:36.014Z"},"license":"MIT","keywords":["404","breakout","game","canvas"],"description":"Core Breakout404 game engine - a Breakout-style 404 page game","maintainers":[{"name":"3rg0n","email":"ergoncopeland@hotmail.com"}],"readme":"# @3rg0n/breakout404-core\n\nFramework-agnostic core for [Breakout404](https://github.com/3rg0n/breakout404) — a customizable 404 page game where visitors destroy blocks arranged to spell \"404\".\n\n**[Live Demo](https://3rg0n.github.io/breakout404/)** · **[Try the 404 page](https://3rg0n.github.io/breakout404/play)**\n\nNo dependencies. Renders to a canvas inside any container element.\n\n## Installation\n\n```bash\nnpm install @3rg0n/breakout404-core\n```\n\nFor React or Vue, use the wrapper packages instead: [`@3rg0n/breakout404-react`](https://www.npmjs.com/package/@3rg0n/breakout404-react) · [`@3rg0n/breakout404-vue`](https://www.npmjs.com/package/@3rg0n/breakout404-vue)\n\n## Usage\n\n```html\n<div id=\"game\" style=\"width: 100%; height: 100vh;\"></div>\n<script type=\"module\">\n  import { Breakout404Game } from '@3rg0n/breakout404-core';\n\n  const game = new Breakout404Game('#game', {\n    difficulty: 'medium',\n    showScore: true,\n  });\n</script>\n```\n\nThe first argument accepts a CSS selector or an `HTMLElement`.\n\n### Cleanup\n\n```js\ngame.destroy();\n```\n\n`destroy()` removes all event listeners and cancels the animation frame. Call it when tearing down the container — in React/Vue this is handled for you by the wrappers.\n\n### Updating options at runtime\n\n```js\ngame.updateOptions({ difficulty: 'hard' });\n```\n\nRe-applies options to the running instance without recreating it.\n\n## Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `theme` | `Partial<Breakout404Theme>` | See below | Customize colors and fonts |\n| `difficulty` | `'easy' \\| 'medium' \\| 'hard'` | `'medium'` | Game difficulty |\n| `showScore` | `boolean` | `true` | Show score and lives |\n| `onComplete` | `() => void` | - | Callback when all blocks destroyed |\n| `onBlockDestroyed` | `(remaining: number) => void` | - | Callback when a block is destroyed |\n| `redirectUrl` | `string` | - | URL to redirect after completion (http/https/relative only) |\n| `redirectDelay` | `number` | `2000` | Delay before redirect (ms) |\n| `logger` | `Breakout404Logger` | - | Optional structured logger for game lifecycle events |\n\n### Theme\n\n```typescript\ninterface Breakout404Theme {\n  background: string;         // Canvas background color\n  paddle: string;             // Paddle color\n  ball: string;               // Ball color\n  blocks: string | string[];  // Block color(s) - array cycles per row\n  text: string;               // Text color for score/messages\n  font: string;               // Font family\n}\n```\n\nDefault:\n\n```js\n{\n  background: '#0a0a0a',\n  paddle: '#ffffff',\n  ball: '#ffffff',\n  blocks: ['#ff6b6b', '#feca57', '#48dbfb', '#ff9ff3', '#54a0ff'],\n  text: '#ffffff',\n  font: 'monospace',\n}\n```\n\n### Difficulty\n\n| Difficulty | Ball Speed | Paddle Width | Lives |\n|------------|------------|--------------|-------|\n| Easy | 4 | 120px | 5 |\n| Medium | 6 | 100px | 3 |\n| Hard | 8 | 80px | 2 |\n\n## Pure engine API\n\nThe game logic is a set of pure functions in `engine.ts`, separate from all DOM and canvas concerns. Use these directly to drive the simulation yourself or to test against it without a browser:\n\n```ts\nimport {\n  createInitialState,\n  startOrRestart,\n  step,\n  countActiveBlocks,\n  DIFFICULTY_SETTINGS,\n  MAX_CANVAS_DIM,\n  TARGET_FRAME_MS,\n} from '@3rg0n/breakout404-core';\n```\n\n`step()` advances one frame and returns `GameEvent` values (block destroyed, life lost, win, game over) for the caller to interpret. It performs no side effects.\n\n## Controls\n\n- **Mouse/Touch** — move paddle by moving cursor/finger\n- **Arrow keys / A,D** — move paddle left/right\n- **Space / Click** — start, or restart after game over\n\n## Security\n\n`redirectUrl` is validated — only `http:`, `https:`, and relative paths are accepted; `javascript:`, `data:` and other dangerous protocols are rejected. The validator is exported for reuse and is SSR-safe:\n\n```ts\nimport { isValidRedirectUrl } from '@3rg0n/breakout404-core';\n\nisValidRedirectUrl('/home');                              // true\nisValidRedirectUrl('javascript:alert(1)');                // false\nisValidRedirectUrl('/home', 'https://example.com');       // explicit base, no window needed\n```\n\nCanvas dimensions are capped at 4096px to prevent GPU/memory exhaustion. See the [threat model](https://github.com/3rg0n/breakout404/blob/master/THREAT_MODEL.md).\n\n## License\n\n[MIT](https://github.com/3rg0n/breakout404/blob/master/LICENSE)\n","readmeFilename":""}