waitless-api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/games/base.ts","../src/games/tetris.ts","../src/games/snake.ts","../src/games/breakout.ts","../src/utils/index.ts","../src/ads/AdPlayer.ts","../src/core.ts","../src/games/index.ts"],"sourcesContent":["import { ThemeType } from '../core';\n\nexport interface GameConfig {\n container: HTMLElement;\n theme?: ThemeType;\n onScore?: (score: number) => void;\n /** Backend/sync: dimensions and speed */\n width?: number;\n height?: number;\n speed?: number;\n /** Game-specific (Tetris: blockSize, scoring; Snake: gridSize, foodValue; Breakout: paddleWidth, brickRows, ballSpeed) */\n [key: string]: any;\n}\n\n/**\n * Base game class with common functionality\n */\nexport abstract class BaseGame {\n protected container: HTMLElement;\n protected theme: ThemeType;\n protected isRunning: boolean = false;\n protected score: number = 0;\n protected onScoreCallback?: (score: number) => void;\n \n constructor(config: GameConfig) {\n this.container = config.container;\n this.theme = config.theme || 'default';\n this.onScoreCallback = config.onScore;\n }\n \n /**\n * Start the game\n */\n abstract start(): void;\n \n /**\n * Pause the game\n */\n abstract pause(): void;\n \n /**\n * Resume the game\n */\n abstract resume(): void;\n \n /**\n * Destroy the game and clean up\n */\n abstract destroy(): void;\n \n /**\n * Update the score and trigger callback\n * @param points Points to add to the score\n */\n protected updateScore(points: number): void {\n this.score += points;\n \n // Call score callback if provided\n if (this.onScoreCallback && typeof this.onScoreCallback === 'function') {\n this.onScoreCallback(this.score);\n }\n }\n \n /**\n * Get the current score\n * @returns Current score\n */\n getScore(): number {\n return this.score;\n }\n \n /**\n * Check if the game is currently running\n * @returns Whether the game is running\n */\n isActive(): boolean {\n return this.isRunning;\n }\n} ","import { BaseGame, GameConfig } from './base';\n\n/**\n * Tetris game implementation\n */\nexport default class TetrisGame extends BaseGame {\n // Game canvas and context\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n \n // Game state\n private grid: number[][] = [];\n private currentPiece: any = null;\n private nextPiece: any = null;\n private animationFrame: number | null = null;\n private lastTime: number = 0;\n private dropInterval: number = 1000;\n private dropCounter: number = 0;\n \n // Game dimensions (from config or defaults)\n private cols: number;\n private rows: number;\n private blockSize: number;\n private scoring: { singleLine: number; doubleLine: number; tripleLine: number; tetris: number };\n \n // Tetromino shapes and colors\n private readonly shapes = [\n // I-piece\n [\n [0, 0, 0, 0],\n [1, 1, 1, 1],\n [0, 0, 0, 0],\n [0, 0, 0, 0]\n ],\n // J-piece\n [\n [2, 0, 0],\n [2, 2, 2],\n [0, 0, 0]\n ],\n // L-piece\n [\n [0, 0, 3],\n [3, 3, 3],\n [0, 0, 0]\n ],\n // O-piece\n [\n [4, 4],\n [4, 4]\n ],\n // S-piece\n [\n [0, 5, 5],\n [5, 5, 0],\n [0, 0, 0]\n ],\n // T-piece\n [\n [0, 6, 0],\n [6, 6, 6],\n [0, 0, 0]\n ],\n // Z-piece\n [\n [7, 7, 0],\n [0, 7, 7],\n [0, 0, 0]\n ]\n ];\n \n private readonly colors = [\n 'transparent',\n '#00FFFF', // I-piece (cyan)\n '#0000FF', // J-piece (blue)\n '#FF8000', // L-piece (orange)\n '#FFFF00', // O-piece (yellow)\n '#00FF00', // S-piece (green)\n '#8000FF', // T-piece (purple)\n '#FF0000' // Z-piece (red)\n ];\n \n constructor(config: GameConfig) {\n super(config);\n\n this.blockSize = typeof config.blockSize === 'number' ? config.blockSize : 30;\n const width = typeof config.width === 'number' ? config.width : 300;\n const height = typeof config.height === 'number' ? config.height : 600;\n this.cols = Math.floor(width / this.blockSize) || 10;\n this.rows = Math.floor(height / this.blockSize) || 20;\n const speed = typeof config.speed === 'number' ? config.speed : 1;\n this.scoring = config.scoring && typeof config.scoring === 'object'\n ? {\n singleLine: config.scoring.singleLine ?? 100,\n doubleLine: config.scoring.doubleLine ?? 300,\n tripleLine: config.scoring.tripleLine ?? 500,\n tetris: config.scoring.tetris ?? 800\n }\n : { singleLine: 100, doubleLine: 300, tripleLine: 500, tetris: 800 };\n\n this.dropInterval = Math.max(100, 1000 / speed);\n\n this.canvas = document.createElement('canvas');\n this.canvas.width = this.cols * this.blockSize;\n this.canvas.height = this.rows * this.blockSize;\n this.canvas.style.display = 'block';\n this.canvas.style.margin = '0 auto';\n this.canvas.style.border = '1px solid #333';\n this.container.appendChild(this.canvas);\n \n const ctx = this.canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Could not get canvas context');\n }\n this.ctx = ctx;\n \n // Initialize game grid\n this.resetGrid();\n \n // Set up event listeners\n this.setupControls();\n }\n \n /**\n * Start the game\n */\n start(): void {\n if (this.isRunning) {\n return;\n }\n \n this.isRunning = true;\n this.resetGrid();\n this.createPiece();\n this.lastTime = 0;\n this.score = 0;\n \n // Start game loop\n this.update(0);\n }\n \n /**\n * Pause the game\n */\n pause(): void {\n if (!this.isRunning || !this.animationFrame) {\n return;\n }\n \n this.isRunning = false;\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n \n /**\n * Resume the game\n */\n resume(): void {\n if (this.isRunning) {\n return;\n }\n \n this.isRunning = true;\n this.lastTime = 0;\n this.update(0);\n }\n \n /**\n * Destroy the game and clean up\n */\n destroy(): void {\n // Stop game loop\n if (this.animationFrame) {\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n \n // Remove event listeners\n window.removeEventListener('keydown', this.handleKeyDown);\n \n // Remove canvas\n if (this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n \n this.isRunning = false;\n }\n \n /**\n * Main game update loop\n */\n private update(time: number): void {\n if (!this.isRunning) {\n return;\n }\n \n const deltaTime = time - this.lastTime;\n this.lastTime = time;\n \n // Update drop counter\n this.dropCounter += deltaTime;\n if (this.dropCounter > this.dropInterval) {\n this.dropPiece();\n }\n \n // Draw game\n this.draw();\n \n // Continue game loop\n this.animationFrame = requestAnimationFrame(this.update.bind(this));\n }\n \n /**\n * Draw the game state\n */\n private draw(): void {\n // Clear canvas\n this.ctx.fillStyle = '#000';\n this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);\n \n // Draw grid\n this.drawGrid();\n \n // Draw current piece\n if (this.currentPiece) {\n this.drawPiece(this.currentPiece);\n }\n }\n \n /**\n * Draw the game grid\n */\n private drawGrid(): void {\n for (let y = 0; y < this.rows; y++) {\n for (let x = 0; x < this.cols; x++) {\n const value = this.grid[y][x];\n if (value !== 0) {\n this.ctx.fillStyle = this.colors[value];\n this.ctx.fillRect(\n x * this.blockSize,\n y * this.blockSize,\n this.blockSize,\n this.blockSize\n );\n \n // Draw outline\n this.ctx.strokeStyle = '#222';\n this.ctx.strokeRect(\n x * this.blockSize,\n y * this.blockSize,\n this.blockSize,\n this.blockSize\n );\n }\n }\n }\n }\n \n /**\n * Draw a tetromino piece\n */\n private drawPiece(piece: any): void {\n const { shape, pos } = piece;\n \n for (let y = 0; y < shape.length; y++) {\n for (let x = 0; x < shape[y].length; x++) {\n const value = shape[y][x];\n if (value !== 0) {\n this.ctx.fillStyle = this.colors[value];\n this.ctx.fillRect(\n (pos.x + x) * this.blockSize,\n (pos.y + y) * this.blockSize,\n this.blockSize,\n this.blockSize\n );\n \n // Draw outline\n this.ctx.strokeStyle = '#222';\n this.ctx.strokeRect(\n (pos.x + x) * this.blockSize,\n (pos.y + y) * this.blockSize,\n this.blockSize,\n this.blockSize\n );\n }\n }\n }\n }\n \n /**\n * Reset the game grid\n */\n private resetGrid(): void {\n this.grid = Array(this.rows).fill(0).map(() => Array(this.cols).fill(0));\n }\n \n /**\n * Create a new tetromino piece\n */\n private createPiece(): void {\n // If we have a next piece, use it\n if (this.nextPiece) {\n this.currentPiece = this.nextPiece;\n this.nextPiece = null;\n } else {\n // Create a new random piece\n const shapeIndex = Math.floor(Math.random() * this.shapes.length);\n this.currentPiece = {\n shape: this.shapes[shapeIndex],\n pos: { x: Math.floor(this.cols / 2) - 1, y: 0 }\n };\n }\n \n // Create the next piece\n const nextShapeIndex = Math.floor(Math.random() * this.shapes.length);\n this.nextPiece = {\n shape: this.shapes[nextShapeIndex],\n pos: { x: Math.floor(this.cols / 2) - 1, y: 0 }\n };\n \n // Check for game over\n if (this.checkCollision()) {\n // Game over\n this.isRunning = false;\n this.resetGrid();\n }\n }\n \n /**\n * Move the current piece down\n */\n private dropPiece(): void {\n this.currentPiece.pos.y++;\n this.dropCounter = 0;\n \n if (this.checkCollision()) {\n // Revert position\n this.currentPiece.pos.y--;\n \n // Merge piece with grid\n this.mergePiece();\n \n // Check for completed lines\n this.checkLines();\n \n // Create new piece\n this.createPiece();\n }\n }\n \n /**\n * Check if the current piece collides with the grid or boundaries\n */\n private checkCollision(): boolean {\n const { shape, pos } = this.currentPiece;\n \n for (let y = 0; y < shape.length; y++) {\n for (let x = 0; x < shape[y].length; x++) {\n if (shape[y][x] !== 0) {\n const gridX = pos.x + x;\n const gridY = pos.y + y;\n \n // Check boundaries\n if (gridX < 0 || gridX >= this.cols || gridY >= this.rows) {\n return true;\n }\n \n // Check collision with existing blocks\n if (gridY >= 0 && this.grid[gridY][gridX] !== 0) {\n return true;\n }\n }\n }\n }\n \n return false;\n }\n \n /**\n * Merge the current piece with the grid\n */\n private mergePiece(): void {\n const { shape, pos } = this.currentPiece;\n \n for (let y = 0; y < shape.length; y++) {\n for (let x = 0; x < shape[y].length; x++) {\n const value = shape[y][x];\n if (value !== 0) {\n const gridY = pos.y + y;\n const gridX = pos.x + x;\n \n // Only merge if within bounds\n if (gridY >= 0 && gridY < this.rows && gridX >= 0 && gridX < this.cols) {\n this.grid[gridY][gridX] = value;\n }\n }\n }\n }\n }\n \n /**\n * Check for completed lines and remove them\n */\n private checkLines(): void {\n let linesCleared = 0;\n \n for (let y = this.rows - 1; y >= 0; y--) {\n // Check if row is full\n if (this.grid[y].every(value => value !== 0)) {\n // Remove the line\n this.grid.splice(y, 1);\n \n // Add a new empty line at the top\n this.grid.unshift(Array(this.cols).fill(0));\n \n // Increment counter and check the same row again (since we moved rows down)\n linesCleared++;\n y++;\n }\n }\n \n if (linesCleared > 0) {\n const pts = [0, this.scoring.singleLine, this.scoring.doubleLine, this.scoring.tripleLine, this.scoring.tetris][linesCleared] ?? this.scoring.tetris;\n this.updateScore(pts);\n }\n }\n \n /**\n * Move the current piece left or right\n */\n private movePiece(dir: number): void {\n this.currentPiece.pos.x += dir;\n \n if (this.checkCollision()) {\n this.currentPiece.pos.x -= dir;\n }\n }\n \n /**\n * Rotate the current piece\n */\n private rotatePiece(): void {\n // Save current position\n const pos = this.currentPiece.pos.x;\n \n // Rotate matrix\n const rotated: number[][] = [];\n const shape = this.currentPiece.shape;\n \n for (let y = 0; y < shape[0].length; y++) {\n const row: number[] = [];\n for (let x = 0; x < shape.length; x++) {\n row.push(shape[shape.length - 1 - x][y]);\n }\n rotated.push(row);\n }\n \n // Apply rotation\n this.currentPiece.shape = rotated;\n \n // Check for collision and adjust if needed\n let offset = 1;\n while (this.checkCollision()) {\n this.currentPiece.pos.x += offset;\n offset = -(offset + (offset > 0 ? 1 : -1));\n \n // If we've tried moving too far, revert rotation\n if (offset > shape[0].length) {\n this.currentPiece.shape = shape;\n this.currentPiece.pos.x = pos;\n return;\n }\n }\n }\n \n /**\n * Handle keyboard input\n */\n private handleKeyDown = (e: KeyboardEvent): void => {\n if (!this.isRunning) {\n return;\n }\n \n switch (e.key) {\n case 'ArrowLeft':\n this.movePiece(-1);\n break;\n case 'ArrowRight':\n this.movePiece(1);\n break;\n case 'ArrowDown':\n this.dropPiece();\n break;\n case 'ArrowUp':\n this.rotatePiece();\n break;\n case ' ': // Space - hard drop\n while (!this.checkCollision()) {\n this.currentPiece.pos.y++;\n }\n this.currentPiece.pos.y--;\n this.mergePiece();\n this.checkLines();\n this.createPiece();\n break;\n }\n };\n \n /**\n * Set up control event listeners\n */\n private setupControls(): void {\n window.addEventListener('keydown', this.handleKeyDown);\n \n // Mobile touch controls could be added here\n }\n} ","import { BaseGame, GameConfig } from './base';\n\ntype Direction = 'up' | 'down' | 'left' | 'right';\n\ninterface GridCell {\n x: number;\n y: number;\n}\n\n// Simple theme colors for snake/food (SDK has theme string only)\nconst THEME_COLORS: Record<string, { primary: string; secondary: string; accent: string; text: string }> = {\n default: { primary: '#333333', secondary: '#666666', accent: '#4caf50', text: '#222222' },\n cyberpunk: { primary: '#ff00ff', secondary: '#00ffff', accent: '#ffff00', text: '#ffffff' },\n minimal: { primary: '#000000', secondary: '#333333', accent: '#555555', text: '#111111' },\n corporate: { primary: '#3f51b5', secondary: '#7986cb', accent: '#ff4081', text: '#263238' }\n};\n\n/**\n * Snake game implementation\n */\nexport default class SnakeGame extends BaseGame {\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n\n private snake: GridCell[] = [];\n private food: GridCell | null = null;\n private direction: Direction = 'right';\n private nextDirection: Direction = 'right';\n private animationFrame: number | null = null;\n private lastTime: number = 0;\n private moveInterval: number = 200;\n private moveCounter: number = 0;\n private highScore: number = 0;\n\n private gridSize: number;\n private cellSize: number;\n private gridWidth: number;\n private gridHeight: number;\n private foodValue: number;\n\n private touchStartX: number = 0;\n private touchStartY: number = 0;\n\n constructor(config: GameConfig) {\n super(config);\n\n this.gridSize = typeof config.gridSize === 'number' ? config.gridSize : 20;\n this.foodValue = typeof config.foodValue === 'number' ? config.foodValue : 10;\n const width = typeof config.width === 'number' ? config.width : 400;\n const height = typeof config.height === 'number' ? config.height : 400;\n this.gridWidth = this.gridSize;\n this.gridHeight = this.gridSize;\n this.cellSize = Math.max(10, Math.floor(Math.min(width, height) / this.gridSize)) || 20;\n this.moveInterval = typeof config.speed === 'number' && config.speed > 0\n ? Math.max(80, 200 / config.speed)\n : 200;\n this.canvas = document.createElement('canvas');\n this.canvas.width = this.gridWidth * this.cellSize;\n this.canvas.height = this.gridHeight * this.cellSize;\n this.canvas.style.display = 'block';\n this.canvas.style.margin = '0 auto';\n this.canvas.style.border = '1px solid #333';\n this.container.appendChild(this.canvas);\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Could not get canvas context');\n }\n this.ctx = ctx;\n\n this.setupControls();\n }\n\n private getColors() {\n return THEME_COLORS[this.theme] || THEME_COLORS.default;\n }\n\n start(): void {\n if (this.isRunning) {\n return;\n }\n this.isRunning = true;\n this.resetGame();\n this.lastTime = 0;\n this.score = 0;\n this.moveInterval = 200;\n this.update(0);\n }\n\n pause(): void {\n if (!this.isRunning || !this.animationFrame) {\n return;\n }\n this.isRunning = false;\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n\n resume(): void {\n if (this.isRunning) {\n return;\n }\n this.isRunning = true;\n this.lastTime = 0;\n this.update(0);\n }\n\n destroy(): void {\n if (this.animationFrame) {\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n window.removeEventListener('keydown', this.handleKeyDown);\n window.removeEventListener('touchstart', this.handleTouchStart);\n window.removeEventListener('touchend', this.handleTouchEnd);\n if (this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n this.isRunning = false;\n }\n\n private update(time: number): void {\n if (!this.isRunning) return;\n\n const deltaTime = time - this.lastTime;\n this.lastTime = time;\n this.moveCounter += deltaTime;\n\n if (this.moveCounter >= this.moveInterval) {\n this.direction = this.nextDirection;\n this.moveSnake();\n this.moveCounter = 0;\n }\n\n this.draw();\n this.animationFrame = requestAnimationFrame(this.update.bind(this));\n }\n\n private draw(): void {\n const colors = this.getColors();\n this.ctx.fillStyle = '#0a0a0a';\n this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);\n\n // Subtle grid\n this.ctx.strokeStyle = colors.text;\n this.ctx.globalAlpha = 0.15;\n for (let i = 0; i <= this.gridWidth; i++) {\n this.ctx.beginPath();\n this.ctx.moveTo(i * this.cellSize, 0);\n this.ctx.lineTo(i * this.cellSize, this.canvas.height);\n this.ctx.stroke();\n }\n for (let j = 0; j <= this.gridHeight; j++) {\n this.ctx.beginPath();\n this.ctx.moveTo(0, j * this.cellSize);\n this.ctx.lineTo(this.canvas.width, j * this.cellSize);\n this.ctx.stroke();\n }\n this.ctx.globalAlpha = 1;\n\n // Food\n if (this.food) {\n this.ctx.fillStyle = colors.secondary;\n this.ctx.fillRect(\n this.food.x * this.cellSize + 1,\n this.food.y * this.cellSize + 1,\n this.cellSize - 2,\n this.cellSize - 2\n );\n }\n\n // Snake body\n for (let i = 0; i < this.snake.length; i++) {\n const seg = this.snake[i];\n const isHead = i === this.snake.length - 1;\n this.ctx.fillStyle = isHead ? colors.accent : colors.primary;\n this.ctx.fillRect(\n seg.x * this.cellSize + 1,\n seg.y * this.cellSize + 1,\n this.cellSize - 2,\n this.cellSize - 2\n );\n }\n\n // Score\n this.ctx.fillStyle = colors.text;\n this.ctx.font = '14px Arial';\n this.ctx.fillText(`Score: ${this.score} High: ${this.highScore}`, 8, 18);\n }\n\n private resetGame(): void {\n const cx = Math.floor(this.gridWidth / 2);\n const cy = Math.floor(this.gridHeight / 2);\n this.snake = [\n { x: cx - 2, y: cy },\n { x: cx - 1, y: cy },\n { x: cx, y: cy }\n ];\n this.direction = 'right';\n this.nextDirection = 'right';\n this.spawnFood();\n }\n\n private spawnFood(): void {\n const empty: GridCell[] = [];\n for (let y = 0; y < this.gridHeight; y++) {\n for (let x = 0; x < this.gridWidth; x++) {\n if (!this.snake.some(s => s.x === x && s.y === y)) {\n empty.push({ x, y });\n }\n }\n }\n if (empty.length === 0) {\n this.food = null;\n return;\n }\n this.food = empty[Math.floor(Math.random() * empty.length)];\n }\n\n private moveSnake(): void {\n const head = this.snake[this.snake.length - 1];\n let nx = head.x;\n let ny = head.y;\n\n switch (this.direction) {\n case 'up': ny--; break;\n case 'down': ny++; break;\n case 'left': nx--; break;\n case 'right': nx++; break;\n }\n\n // Wall collision\n if (nx < 0 || nx >= this.gridWidth || ny < 0 || ny >= this.gridHeight) {\n this.gameOver();\n return;\n }\n\n // Self collision\n if (this.snake.some(s => s.x === nx && s.y === ny)) {\n this.gameOver();\n return;\n }\n\n this.snake.push({ x: nx, y: ny });\n\n // Food collision\n if (this.food && this.food.x === nx && this.food.y === ny) {\n this.updateScore(this.foodValue);\n if (this.score > this.highScore) this.highScore = this.score;\n this.spawnFood();\n if (this.moveInterval > 80) {\n this.moveInterval -= 5;\n }\n } else {\n this.snake.shift();\n }\n }\n\n private gameOver(): void {\n this.isRunning = false;\n if (this.animationFrame) {\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n }\n\n private handleKeyDown = (e: KeyboardEvent): void => {\n if (!this.isRunning) return;\n const current = this.nextDirection;\n switch (e.key) {\n case 'ArrowUp':\n if (current !== 'down') this.nextDirection = 'up';\n break;\n case 'ArrowDown':\n if (current !== 'up') this.nextDirection = 'down';\n break;\n case 'ArrowLeft':\n if (current !== 'right') this.nextDirection = 'left';\n break;\n case 'ArrowRight':\n if (current !== 'left') this.nextDirection = 'right';\n break;\n }\n e.preventDefault();\n };\n\n private handleTouchStart = (e: TouchEvent): void => {\n if (e.touches.length > 0) {\n this.touchStartX = e.touches[0].clientX;\n this.touchStartY = e.touches[0].clientY;\n }\n };\n\n private handleTouchEnd = (e: TouchEvent): void => {\n if (!this.isRunning || !e.changedTouches || e.changedTouches.length === 0) return;\n const dx = e.changedTouches[0].clientX - this.touchStartX;\n const dy = e.changedTouches[0].clientY - this.touchStartY;\n const minSwipe = 30;\n if (Math.abs(dx) > Math.abs(dy)) {\n if (dx > minSwipe && this.nextDirection !== 'left') this.nextDirection = 'right';\n else if (dx < -minSwipe && this.nextDirection !== 'right') this.nextDirection = 'left';\n } else {\n if (dy > minSwipe && this.nextDirection !== 'up') this.nextDirection = 'down';\n else if (dy < -minSwipe && this.nextDirection !== 'down') this.nextDirection = 'up';\n }\n };\n\n private setupControls(): void {\n window.addEventListener('keydown', this.handleKeyDown);\n window.addEventListener('touchstart', this.handleTouchStart, { passive: true });\n window.addEventListener('touchend', this.handleTouchEnd, { passive: true });\n }\n}\n","import { BaseGame, GameConfig } from './base';\n\ninterface Brick {\n x: number;\n y: number;\n width: number;\n height: number;\n visible: boolean;\n color: string;\n points: number;\n}\n\nconst THEME_COLORS: Record<string, { primary: string; secondary: string; accent: string; text: string }> = {\n default: { primary: '#333333', secondary: '#666666', accent: '#4caf50', text: '#222222' },\n cyberpunk: { primary: '#ff00ff', secondary: '#00ffff', accent: '#ffff00', text: '#ffffff' },\n minimal: { primary: '#000000', secondary: '#333333', accent: '#555555', text: '#111111' },\n corporate: { primary: '#3f51b5', secondary: '#7986cb', accent: '#ff4081', text: '#263238' }\n};\n\n/**\n * Breakout game implementation\n */\nexport default class BreakoutGame extends BaseGame {\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n\n private paddle: { x: number; y: number; width: number; height: number };\n private ball: { x: number; y: number; dx: number; dy: number; radius: number };\n private bricks: Brick[] = [];\n private animationFrame: number | null = null;\n private lastTime: number = 0;\n private ballLaunched: boolean = false;\n private lives: number = 3;\n private level: number = 1;\n private highScore: number = 0;\n private paused: boolean = false;\n\n private readonly width: number;\n private readonly height: number;\n private readonly paddleWidth: number;\n private readonly paddleHeight: number = 10;\n private readonly ballRadius: number = 8;\n private readonly brickRows: number;\n private readonly brickColumns: number;\n private baseBallSpeed: number;\n private brickPadding: number = 8;\n private brickOffsetTop: number = 50;\n\n constructor(config: GameConfig) {\n super(config);\n\n this.width = typeof config.width === 'number' ? config.width : 480;\n this.height = typeof config.height === 'number' ? config.height : 320;\n this.paddleWidth = typeof config.paddleWidth === 'number' ? config.paddleWidth : 100;\n this.brickRows = typeof config.brickRows === 'number' ? config.brickRows : 5;\n this.brickColumns = typeof config.brickColumns === 'number' ? config.brickColumns : 8;\n this.baseBallSpeed = typeof config.ballSpeed === 'number' && config.ballSpeed > 0 ? config.ballSpeed : 5;\n\n this.canvas = document.createElement('canvas');\n this.canvas.width = this.width;\n this.canvas.height = this.height;\n this.canvas.style.display = 'block';\n this.canvas.style.margin = '0 auto';\n this.canvas.style.border = '1px solid #333';\n this.container.appendChild(this.canvas);\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) throw new Error('Could not get canvas context');\n this.ctx = ctx;\n\n this.paddle = {\n x: this.width / 2 - this.paddleWidth / 2,\n y: this.height - 25,\n width: this.paddleWidth,\n height: this.paddleHeight\n };\n\n this.ball = {\n x: this.width / 2,\n y: this.height - 40,\n dx: 0,\n dy: 0,\n radius: this.ballRadius\n };\n\n this.setupControls();\n }\n\n private getColors() {\n return THEME_COLORS[this.theme] || THEME_COLORS.default;\n }\n\n start(): void {\n if (this.isRunning) return;\n this.isRunning = true;\n this.lives = 3;\n this.level = 1;\n this.score = 0;\n this.ballLaunched = false;\n this.baseBallSpeed = 5;\n this.resetGame();\n this.lastTime = 0;\n this.update(0);\n }\n\n pause(): void {\n if (!this.isRunning || !this.animationFrame) return;\n this.paused = true;\n this.isRunning = false;\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n\n resume(): void {\n if (this.isRunning) return;\n this.paused = false;\n this.isRunning = true;\n this.lastTime = 0;\n this.update(0);\n }\n\n destroy(): void {\n if (this.animationFrame) {\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n this.canvas.removeEventListener('mousemove', this.handleMouseMove);\n this.canvas.removeEventListener('touchmove', this.handleTouchMove);\n this.canvas.removeEventListener('click', this.handleClick);\n window.removeEventListener('keydown', this.handleKeyDown);\n if (this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n this.isRunning = false;\n }\n\n private update(time: number): void {\n if (!this.isRunning) {\n this.draw();\n this.animationFrame = requestAnimationFrame(this.update.bind(this));\n return;\n }\n\n const deltaTime = Math.min(time - this.lastTime, 50);\n this.lastTime = time;\n\n if (!this.paused && this.ballLaunched) {\n this.updateGameState(deltaTime);\n }\n\n this.draw();\n this.animationFrame = requestAnimationFrame(this.update.bind(this));\n }\n\n private initBricks(): void {\n const colors = this.getColors();\n const rowColors = [colors.primary, colors.secondary, colors.accent];\n const brickW = (this.width - this.brickPadding * (this.brickColumns + 1)) / this.brickColumns;\n const brickH = 18;\n\n this.bricks = [];\n for (let r = 0; r < this.brickRows; r++) {\n for (let c = 0; c < this.brickColumns; c++) {\n const points = this.brickRows - r;\n this.bricks.push({\n x: this.brickPadding + c * (brickW + this.brickPadding),\n y: this.brickOffsetTop + r * (brickH + this.brickPadding),\n width: brickW,\n height: brickH,\n visible: true,\n color: rowColors[r % rowColors.length],\n points\n });\n }\n }\n }\n\n private resetGame(): void {\n this.initBricks();\n this.paddle.x = this.width / 2 - this.paddle.width / 2;\n this.paddle.y = this.height - 25;\n const speed = this.baseBallSpeed;\n this.ball.x = this.width / 2;\n this.ball.y = this.height - 40;\n this.ball.dx = 0;\n this.ball.dy = 0;\n this.ballLaunched = false;\n }\n\n private launchBall(): void {\n if (this.ballLaunched) return;\n this.ballLaunched = true;\n const speed = this.baseBallSpeed;\n this.ball.dx = speed * 0.6;\n this.ball.dy = -speed;\n }\n\n private updateGameState(deltaTime: number): void {\n this.ball.x += this.ball.dx;\n this.ball.y += this.ball.dy;\n\n if (this.ball.x - this.ball.radius < 0) {\n this.ball.x = this.ball.radius;\n this.ball.dx = -this.ball.dx;\n }\n if (this.ball.x + this.ball.radius > this.width) {\n this.ball.x = this.width - this.ball.radius;\n this.ball.dx = -this.ball.dx;\n }\n if (this.ball.y - this.ball.radius < 0) {\n this.ball.y = this.ball.radius;\n this.ball.dy = -this.ball.dy;\n }\n\n if (this.ball.y + this.ball.radius > this.paddle.y &&\n this.ball.y - this.ball.radius < this.paddle.y + this.paddle.height &&\n this.ball.x >= this.paddle.x &&\n this.ball.x <= this.paddle.x + this.paddle.width) {\n const hitPos = (this.ball.x - (this.paddle.x + this.paddle.width / 2)) / (this.paddle.width / 2);\n this.ball.dy = -Math.abs(this.ball.dy);\n this.ball.dx = this.baseBallSpeed * 0.8 * hitPos;\n this.ball.y = this.paddle.y - this.ball.radius;\n }\n\n if (this.ball.y + this.ball.radius > this.height) {\n this.lives--;\n if (this.lives <= 0) {\n this.isRunning = false;\n if (this.score > this.highScore) this.highScore = this.score;\n return;\n }\n this.ball.x = this.width / 2;\n this.ball.y = this.height - 40;\n this.ball.dx = 0;\n this.ball.dy = 0;\n this.ballLaunched = false;\n return;\n }\n\n for (const brick of this.bricks) {\n if (!brick.visible) continue;\n if (this.ball.x + this.ball.radius > brick.x &&\n this.ball.x - this.ball.radius < brick.x + brick.width &&\n this.ball.y + this.ball.radius > brick.y &&\n this.ball.y - this.ball.radius < brick.y + brick.height) {\n brick.visible = false;\n this.updateScore(brick.points);\n if (this.score > this.highScore) this.highScore = this.score;\n this.ball.dy = -this.ball.dy;\n break;\n }\n }\n\n const visibleCount = this.bricks.filter(b => b.visible).length;\n if (visibleCount === 0) {\n this.level++;\n this.baseBallSpeed = Math.min(this.baseBallSpeed * 1.1, this.baseBallSpeed * 2);\n this.resetGame();\n this.ballLaunched = false;\n }\n }\n\n private draw(): void {\n const colors = this.getColors();\n this.ctx.fillStyle = '#0a0a12';\n this.ctx.fillRect(0, 0, this.width, this.height);\n\n this.bricks.forEach(b => {\n if (!b.visible) return;\n this.ctx.fillStyle = b.color;\n this.ctx.fillRect(b.x, b.y, b.width, b.height);\n });\n\n this.ctx.fillStyle = colors.primary;\n this.ctx.fillRect(this.paddle.x, this.paddle.y, this.paddle.width, this.paddle.height);\n\n this.ctx.fillStyle = colors.accent;\n this.ctx.beginPath();\n this.ctx.arc(this.ball.x, this.ball.y, this.ball.radius, 0, Math.PI * 2);\n this.ctx.fill();\n\n this.ctx.fillStyle = colors.text;\n this.ctx.font = '14px Arial';\n this.ctx.fillText(`Lives: ${this.lives} Score: ${this.score} High: ${this.highScore}`, 8, 22);\n this.ctx.fillText(`Level ${this.level}`, this.width - 60, 22);\n\n for (let i = 0; i < this.lives; i++) {\n this.ctx.beginPath();\n this.ctx.arc(8 + i * 14, 38, 5, 0, Math.PI * 2);\n this.ctx.fillStyle = colors.accent;\n this.ctx.fill();\n }\n\n if (this.paused) {\n this.ctx.fillStyle = 'rgba(0,0,0,0.6)';\n this.ctx.fillRect(0, 0, this.width, this.height);\n this.ctx.fillStyle = '#fff';\n this.ctx.font = '24px Arial';\n this.ctx.textAlign = 'center';\n this.ctx.fillText('Paused - Press Space', this.width / 2, this.height / 2);\n this.ctx.textAlign = 'left';\n }\n\n if (!this.isRunning && this.lives <= 0) {\n this.ctx.fillStyle = 'rgba(0,0,0,0.7)';\n this.ctx.fillRect(0, 0, this.width, this.height);\n this.ctx.fillStyle = '#fff';\n this.ctx.font = '28px Arial';\n this.ctx.textAlign = 'center';\n this.ctx.fillText('Game Over', this.width / 2, this.height / 2 - 20);\n this.ctx.font = '16px Arial';\n this.ctx.fillText(`Score: ${this.score}`, this.width / 2, this.height / 2 + 10);\n this.ctx.textAlign = 'left';\n }\n\n if (this.isRunning && !this.ballLaunched) {\n this.ctx.fillStyle = 'rgba(0,0,0,0.4)';\n this.ctx.font = '14px Arial';\n this.ctx.textAlign = 'center';\n this.ctx.fillText('Click or tap to launch', this.width / 2, this.height / 2);\n this.ctx.textAlign = 'left';\n }\n }\n\n private handleMouseMove = (e: MouseEvent): void => {\n const rect = this.canvas.getBoundingClientRect();\n const scaleX = this.canvas.width / rect.width;\n const relativeX = (e.clientX - rect.left) * scaleX;\n this.paddle.x = Math.max(0, Math.min(this.width - this.paddle.width, relativeX - this.paddle.width / 2));\n };\n\n private handleTouchMove = (e: TouchEvent): void => {\n e.preventDefault();\n if (e.touches.length > 0) {\n const rect = this.canvas.getBoundingClientRect();\n const scaleX = this.canvas.width / rect.width;\n const relativeX = (e.touches[0].clientX - rect.left) * scaleX;\n this.paddle.x = Math.max(0, Math.min(this.width - this.paddle.width, relativeX - this.paddle.width / 2));\n }\n };\n\n private handleClick = (): void => {\n this.launchBall();\n };\n\n private handleKeyDown = (e: KeyboardEvent): void => {\n if (e.key === ' ') {\n e.preventDefault();\n if (this.isRunning) {\n if (this.paused) this.resume();\n else this.pause();\n }\n }\n };\n\n private setupControls(): void {\n this.canvas.addEventListener('mousemove', this.handleMouseMove);\n this.canvas.addEventListener('touchmove', this.handleTouchMove, { passive: false });\n this.canvas.addEventListener('click', this.handleClick);\n window.addEventListener('keydown', this.handleKeyDown);\n }\n}\n","import { GameOptions, GameType, ThemeType } from '../core';\n\n/**\n * Validate and normalize game options\n * @param options User-provided game options\n * @returns Validated game options\n */\nexport function validateOptions(options: GameOptions): GameOptions {\n const validatedOptions: GameOptions = { ...options };\n \n // Validate game type\n if (options.game && !isValidGameType(options.game)) {\n console.warn(`Invalid game type: ${options.game}. Defaulting to tetris.`);\n validatedOptions.game = 'tetris';\n }\n \n // Validate theme\n if (options.theme && !isValidThemeType(options.theme)) {\n console.warn(`Invalid theme: ${options.theme}. Defaulting to default theme.`);\n validatedOptions.theme = 'default';\n }\n \n // Ensure message is a string\n if (options.message && typeof options.message !== 'string') {\n validatedOptions.message = String(options.message);\n }\n \n // Validate dimensions\n if (options.width && (typeof options.width !== 'number' || options.width <= 0)) {\n delete validatedOptions.width;\n }\n \n if (options.height && (typeof options.height !== 'number' || options.height <= 0)) {\n delete validatedOptions.height;\n }\n \n return validatedOptions;\n}\n\n/**\n * Check if a game type is valid\n * @param game Game type to validate\n * @returns Whether the game type is valid\n */\nfunction isValidGameType(game: string): game is GameType {\n return ['tetris', 'snake', 'breakout'].includes(game);\n}\n\n/**\n * Check if a theme type is valid\n * @param theme Theme type to validate\n * @returns Whether the theme type is valid\n */\nfunction isValidThemeType(theme: string): theme is ThemeType {\n return ['default', 'cyberpunk', 'minimal', 'corporate'].includes(theme);\n}\n\n/**\n * Preload common assets used by games\n */\nexport function preloadAssets(): void {\n // This would preload images, sounds, etc. needed by the games\n // For now, we'll just create a placeholder implementation\n \n // Example of image preloading\n const imageUrls: string[] = [\n // These would be actual URLs in production\n // 'https://assets.waitlessapi.com/tetris/blocks.png',\n // 'https://assets.waitlessapi.com/common/bg.png'\n ];\n \n imageUrls.forEach(url => {\n const img = new Image();\n img.src = url;\n });\n}\n\n/**\n * Detect browser capabilities and limitations\n * @returns Object with browser capability information\n */\nexport function detectBrowserCapabilities() {\n return {\n touchEnabled: 'ontouchstart' in window || navigator.maxTouchPoints > 0,\n webGLSupport: isWebGLSupported(),\n screenSize: {\n width: window.innerWidth,\n height: window.innerHeight\n }\n };\n}\n\n/**\n * Check if WebGL is supported\n * @returns Whether WebGL is supported\n */\nfunction isWebGLSupported(): boolean {\n try {\n const canvas = document.createElement('canvas');\n return !!(window.WebGLRenderingContext && \n (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));\n } catch (e) {\n return false;\n }\n}\n\n/**\n * Create a throttled function\n * @param callback Function to throttle\n * @param delay Delay in milliseconds\n * @returns Throttled function\n */\nexport function throttle<T extends (...args: any[]) => any>(\n callback: T,\n delay: number\n): (...args: Parameters<T>) => void {\n let lastCall = 0;\n return (...args: Parameters<T>) => {\n const now = Date.now();\n if (now - lastCall >= delay) {\n lastCall = now;\n callback(...args);\n }\n };\n} ","export interface AdConfig {\n adTagUrl: string;\n maxDuration?: number; // seconds\n onAdStarted?: () => void;\n onAdComplete?: () => void;\n onAdError?: (error: any) => void;\n onAdSkipped?: () => void;\n}\n\ndeclare global {\n interface Window {\n google?: {\n ima: {\n AdDisplayContainer: new (container: HTMLElement, videoElement: HTMLVideoElement) => any;\n AdsLoader: new (adDisplayContainer: any) => any;\n AdsManagerLoadedEvent: { Type: { ADS_MANAGER_LOADED: string } };\n AdErrorEvent: { Type: { AD_ERROR: string } };\n AdsRequest: new () => any;\n AdsRenderingSettings: new () => any;\n AdEvent: { Type: { CONTENT_PAUSE_REQUESTED: string; CONTENT_RESUME_REQUESTED: string; ALL_ADS_COMPLETED: string; SKIPPED: string } };\n ViewMode: { NORMAL: number };\n };\n };\n }\n}\n\nexport class AdPlayer {\n private container: HTMLElement;\n private adDisplayContainer: any;\n private adsLoader: any;\n private adsManager: any;\n private videoElement: HTMLVideoElement;\n private adContainer: HTMLElement;\n private loadingOverlay: HTMLElement | null = null;\n private adBadge: HTMLElement | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n this.adDisplayContainer = null;\n this.adsLoader = null;\n this.adsManager = null;\n this.videoElement = null as any;\n this.adContainer = null as any;\n this.setupElements();\n }\n\n private setupElements(): void {\n this.videoElement = document.createElement('video');\n this.videoElement.style.cssText = `\n width: 100%;\n height: 100%;\n object-fit: contain;\n background: #000;\n `;\n\n this.adContainer = document.createElement('div');\n const w = Math.max(this.container.offsetWidth || 1, 1);\n const h = Math.max(this.container.offsetHeight || 1, 1);\n this.adContainer.style.cssText = `\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n min-width: ${w}px;\n min-height: ${h}px;\n `;\n this.adContainer.appendChild(this.videoElement);\n\n this.adBadge = document.createElement('div');\n this.adBadge.textContent = 'Ad';\n this.adBadge.style.cssText = `\n position: absolute;\n top: 8px;\n right: 8px;\n font-size: 10px;\n font-family: sans-serif;\n color: rgba(255,255,255,0.9);\n background: rgba(0,0,0,0.5);\n padding: 2px 6px;\n border-radius: 2px;\n z-index: 10;\n display: none;\n `;\n this.adContainer.appendChild(this.adBadge);\n this.container.appendChild(this.adContainer);\n }\n\n private showLoadingOverlay(): void {\n if (this.loadingOverlay && this.loadingOverlay.parentNode) return;\n this.loadingOverlay = document.createElement('div');\n this.loadingOverlay.setAttribute('aria-live', 'polite');\n this.loadingOverlay.setAttribute('aria-label', 'Loading ad');\n this.loadingOverlay.style.cssText = `\n position: absolute;\n top: 0; left: 0;\n width: 100%; height: 100%;\n background: rgba(0,0,0,0.85);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n z-index: 20;\n color: rgba(255,255,255,0.9);\n font-family: sans-serif;\n font-size: 14px;\n `;\n const spinner = document.createElement('div');\n spinner.style.cssText = `\n width: 32px; height: 32px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top-color: #fff;\n border-radius: 50%;\n animation: ad-spin 0.8s linear infinite;\n `;\n const style = document.createElement('style');\n style.textContent = '@keyframes ad-spin { to { transform: rotate(360deg); } }';\n this.loadingOverlay.appendChild(style);\n this.loadingOverlay.appendChild(spinner);\n const text = document.createElement('span');\n text.textContent = 'Loading ad…';\n this.loadingOverlay.appendChild(text);\n this.container.appendChild(this.loadingOverlay);\n }\n\n private removeLoadingOverlay(): void {\n if (this.loadingOverlay && this.loadingOverlay.parentNode) {\n this.loadingOverlay.parentNode.removeChild(this.loadingOverlay);\n }\n this.loadingOverlay = null;\n }\n\n private showErrorOverlay(thenRun: () => void): void {\n this.removeLoadingOverlay();\n const overlay = document.createElement('div');\n overlay.setAttribute('aria-live', 'polite');\n overlay.setAttribute('aria-label', 'Ad could not load');\n overlay.style.cssText = `\n position: absolute;\n top: 0; left: 0;\n width: 100%; height: 100%;\n background: rgba(0,0,0,0.9);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n z-index: 30;\n color: rgba(255,255,255,0.95);\n font-family: sans-serif;\n font-size: 14px;\n `;\n const message = document.createElement('p');\n message.textContent = \"Ad couldn't load\";\n message.style.margin = '0';\n overlay.appendChild(message);\n const btn = document.createElement('button');\n btn.textContent = 'Continue';\n btn.style.cssText = `\n padding: 8px 20px;\n font-size: 14px;\n cursor: pointer;\n background: rgba(255,255,255,0.2);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.4);\n border-radius: 4px;\n `;\n const run = () => {\n if (overlay.parentNode) overlay.parentNode.removeChild(overlay);\n thenRun();\n };\n btn.addEventListener('click', run);\n overlay.appendChild(btn);\n this.container.appendChild(overlay);\n setTimeout(run, 3000);\n }\n\n async playAd(config: AdConfig): Promise<void> {\n return new Promise((resolve) => {\n this.showLoadingOverlay();\n const onError = () => {\n this.showErrorOverlay(() => {\n this.cleanup();\n resolve();\n });\n };\n if (!(window as any).google?.ima) {\n this.loadIMAScript()\n .then(() => this.initializeAd(config, resolve, onError))\n .catch(() => {\n config.onAdError?.(new Error('Failed to load IMA SDK'));\n onError();\n });\n } else {\n this.initializeAd(config, resolve, onError);\n }\n });\n }\n\n private loadIMAScript(): Promise<void> {\n return new Promise((resolve, reject) => {\n if ((window as any).google?.ima) {\n resolve();\n return;\n }\n\n const script = document.createElement('script');\n script.src = 'https://imasdk.googleapis.com/js/sdkloader/ima3.js';\n script.async = true;\n script.onload = () => resolve();\n script.onerror = () => reject(new Error('Failed to load IMA SDK'));\n document.head.appendChild(script);\n });\n }\n\n private initializeAd(config: AdConfig, resolve: () => void, onError: () => void): void {\n const google = (window as any).google;\n if (!google?.ima) {\n config.onAdError?.(new Error('IMA SDK not available'));\n onError();\n return;\n }\n\n this.adDisplayContainer = new google.ima.AdDisplayContainer(\n this.adContainer,\n this.videoElement\n );\n\n this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer);\n\n this.adsLoader.addEventListener(\n google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,\n (event: any) => this.onAdsManagerLoaded(event, config, resolve, onError),\n false\n );\n\n this.adsLoader.addEventListener(\n google.ima.AdErrorEvent.Type.AD_ERROR,\n (event: any) => {\n console.warn('Ad error:', event.getError());\n config.onAdError?.(event.getError());\n this.showErrorOverlay(() => {\n this.cleanup();\n resolve();\n });\n },\n false\n );\n\n const adsRequest = new google.ima.AdsRequest();\n adsRequest.adTagUrl = config.adTagUrl;\n adsRequest.linearAdSlotWidth = this.container.offsetWidth;\n adsRequest.linearAdSlotHeight = this.container.offsetHeight;\n adsRequest.nonLinearAdSlotWidth = this.container.offsetWidth;\n adsRequest.nonLinearAdSlotHeight = this.container.offsetHeight;\n\n this.adDisplayContainer.initialize();\n this.adsLoader.requestAds(adsRequest);\n }\n\n private onAdsManagerLoaded(event: any, config: AdConfig, resolve: () => void, onError: () => void): void {\n const google = (window as any).google;\n if (!google?.ima) {\n resolve();\n return;\n }\n\n const adsRenderingSettings = new google.ima.AdsRenderingSettings();\n adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;\n\n this.adsManager = event.getAdsManager(this.videoElement, adsRenderingSettings);\n\n this.adsManager.addEventListener(\n google.ima.AdErrorEvent.Type.AD_ERROR,\n (e: any) => {\n console.warn('Ad manager error:', e.getError());\n config.onAdError?.(e.getError());\n this.showErrorOverlay(() => {\n this.cleanup();\n resolve();\n });\n }\n );\n\n this.adsManager.addEventListener(\n google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED,\n () => {\n this.removeLoadingOverlay();\n if (this.adBadge) this.adBadge.style.display = 'block';\n config.onAdStarted?.();\n }\n );\n\n this.adsManager.addEventListener(\n google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,\n () => {\n config.onAdComplete?.();\n this.cleanup();\n resolve();\n }\n );\n\n this.adsManager.addEventListener(\n google.ima.AdEvent.Type.ALL_ADS_COMPLETED,\n () => {\n config.onAdComplete?.();\n this.cleanup();\n resolve();\n }\n );\n\n this.adsManager.addEventListener(\n google.ima.AdEvent.Type.SKIPPED,\n () => {\n config.onAdSkipped?.();\n this.cleanup();\n resolve();\n }\n );\n\n try {\n this.adsManager.init(\n this.container.offsetWidth,\n this.container.offsetHeight,\n google.ima.ViewMode.NORMAL\n );\n this.adsManager.start();\n } catch (error) {\n console.warn('Ad start error:', error);\n config.onAdError?.(error);\n this.showErrorOverlay(() => {\n this.cleanup();\n resolve();\n });\n }\n }\n\n private cleanup(): void {\n if (this.adsManager) {\n try {\n this.adsManager.destroy();\n } catch (_) {}\n this.adsManager = null;\n }\n if (this.adsLoader) {\n try {\n this.adsLoader.destroy();\n } catch (_) {}\n this.adsLoader = null;\n }\n this.removeLoadingOverlay();\n if (this.adContainer && this.adContainer.parentNode) {\n this.adContainer.parentNode.removeChild(this.adContainer);\n }\n this.adBadge = null;\n }\n\n destroy(): void {\n this.cleanup();\n }\n}\n","import { loadGame } from './games';\nimport { GameConfig } from './games/base';\nimport { validateOptions, preloadAssets } from './utils';\nimport { AdPlayer } from './ads/AdPlayer';\n\nexport type GameType = 'tetris' | 'snake' | 'breakout';\nexport type ThemeType = 'default' | 'cyberpunk' | 'minimal' | 'corporate';\n\n/** Ad config shape from dashboard/backend (used by showAd and overrides) */\nexport interface WaitlessConfig {\n strategy?: { preset?: string; behavior?: string };\n frequency?: { minInterval?: number; maxAdsPerSession?: number; maxAdsPerHour?: number };\n duration?: {\n shortThreshold?: number;\n longThreshold?: number;\n adMaxDuration?: number;\n enableGames?: boolean;\n };\n batch?: { enabled?: boolean; showAdOnce?: boolean };\n fallback?: { type?: string; showMessage?: boolean };\n analytics?: { trackEvents?: boolean; enableABTesting?: boolean };\n}\n\nconst CONFIG_CACHE_TTL_MS = 5 * 60 * 1000;\nconst CONFIG_CACHE_KEY_PREFIX = 'waitless_config_';\n\nexport interface GameOptions {\n game?: GameType;\n theme?: ThemeType;\n message?: string;\n container?: HTMLElement | string;\n width?: number;\n height?: number;\n onStart?: () => void;\n onScore?: (score: number) => void;\n onEnd?: () => void;\n showAds?: boolean;\n adTagUrl?: string;\n adDuration?: number;\n adPlacement?: 'pre-game' | 'post-game' | 'both';\n}\n\nconst DEFAULT_AD_TAG_URL = 'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=';\n\nexport class WaitlessAPI {\n private apiKey: string;\n private baseUrl: string;\n private apiBaseUrl: string;\n private defaultAdTagUrl: string;\n private sessionId: string | null = null;\n private container: HTMLElement | null = null;\n private gameInstance: any = null;\n private isPlaying: boolean = false;\n private lastBackendConfig: Record<string, any> | null = null;\n private config: WaitlessConfig | null = null;\n private configLoaded: boolean = false;\n private configPromise: Promise<void> | null = null;\n private batchIdsSeen: Set<string> = new Set();\n private lastAdTime: number = 0;\n private adsThisSession: number = 0;\n private adsThisHour: number = 0;\n private lastHourStart: number = 0;\n\n /**\n * Initialize the WaitlessAPI SDK\n * @param apiKey Your WaitlessAPI key\n * @param baseUrlOrOptions Base URL string or options object with apiBaseUrl (defaults to production)\n */\n constructor(apiKey: string, baseUrlOrOptions: string | { apiBaseUrl?: string } = 'https://api.waitlessapi.com') {\n if (!apiKey) {\n throw new Error('API key is required');\n }\n const baseUrl =\n typeof baseUrlOrOptions === 'string'\n ? baseUrlOrOptions\n : baseUrlOrOptions?.apiBaseUrl ?? 'https://api.waitlessapi.com';\n\n this.apiKey = apiKey;\n this.baseUrl = baseUrl;\n this.apiBaseUrl = baseUrl;\n this.defaultAdTagUrl = DEFAULT_AD_TAG_URL;\n this.configPromise = this.loadConfig();\n\n preloadAssets();\n }\n\n private getDefaultConfig(): WaitlessConfig {\n return {\n strategy: { preset: 'balanced', behavior: 'auto' },\n frequency: { minInterval: 300, maxAdsPerSession: 3, maxAdsPerHour: 6 },\n duration: { shortThreshold: 10, longThreshold: 60, adMaxDuration: 15, enableGames: true },\n batch: { enabled: true, showAdOnce: true },\n fallback: { type: 'spinner', showMessage: true },\n analytics: { trackEvents: true, enableABTesting: false }\n };\n }\n\n private getCachedConfig(): WaitlessConfig | null {\n try {\n const raw = typeof localStorage !== 'undefined' ? localStorage.getItem(CONFIG_CACHE_KEY_PREFIX + this.apiKey) : null;\n if (!raw) return null;\n const { config, timestamp } = JSON.parse(raw) as { config: WaitlessConfig; timestamp: number };\n if (Date.now() - timestamp > CONFIG_CACHE_TTL_MS) return null;\n return config;\n } catch {\n return null;\n }\n }\n\n private cacheConfig(config: WaitlessConfig): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(\n CONFIG_CACHE_KEY_PREFIX + this.apiKey,\n JSON.stringify({ config, timestamp: Date.now() })\n );\n }\n } catch {\n // ignore\n }\n }\n\n private async loadConfig(): Promise<void> {\n const cached = this.getCachedConfig();\n if (cached) {\n this.config = cached;\n this.configLoaded = true;\n return;\n }\n try {\n const url = `${this.apiBaseUrl}/api/keys/${encodeURIComponent(this.apiKey)}/config`;\n const res = await fetch(url);\n if (res.ok) {\n const data = (await res.json()) as WaitlessConfig;\n this.config = data;\n this.cacheConfig(data);\n } else {\n this.config = this.getDefaultConfig();\n }\n } catch {\n this.config = this.getDefaultConfig();\n }\n this.configLoaded = true;\n }\n\n /** Wait for config to be loaded (e.g. before using showAd). */\n private async ensureConfigLoaded(): Promise<void> {\n if (!this.configLoaded && this.configPromise) await this.configPromise;\n }\n\n /** Clear cache and reload config from API. */\n async refreshConfig(): Promise<void> {\n try {\n if (typeof localStorage !== 'undefined') localStorage.removeItem(CONFIG_CACHE_KEY_PREFIX + this.apiKey);\n } catch {\n // ignore\n }\n this.configLoaded = false;\n this.configPromise = this.loadConfig();\n await this.configPromise;\n }\n\n /** Return current config (for debugging). */\n getConfig(): WaitlessConfig | null {\n return this.config;\n }\n\n /**\n * Run processing with a minimal fallback UI (spinner/message). No ad or game.\n */\n private async showProcessing<T>(\n processingFn: () => Promise<T>,\n type: string,\n message: string\n ): Promise<T> {\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.7);display:flex;flex-direction:column;align-items:center;justify-content:center;';\n const text = document.createElement('div');\n text.textContent = message || 'Processing...';\n text.style.cssText = 'color:#fff;font-size:18px;margin-top:12px;';\n const spinner = document.createElement('div');\n spinner.style.cssText =\n 'width:40px;height:40px;border:3px solid rgba(255,255,255,0.3);border-top-color:#fff;border-radius:50%;animation:waitless-spin 0.8s linear infinite;';\n if (!document.getElementById('waitless-spinner-style')) {\n const style = document.createElement('style');\n style.id = 'waitless-spinner-style';\n style.textContent = '@keyframes waitless-spin { to { transform: rotate(360deg); } }';\n document.head.appendChild(style);\n }\n overlay.appendChild(spinner);\n overlay.appendChild(text);\n document.body.appendChild(overlay);\n try {\n return await processingFn();\n } finally {\n overlay.remove();\n }\n }\n\n private shouldShowAd(frequency: WaitlessConfig['frequency']): boolean {\n if (!frequency) return true;\n const now = Date.now();\n const minInterval = (frequency.minInterval ?? 300) * 1000;\n if (now - this.lastAdTime < minInterval) return false;\n const maxSession = frequency.maxAdsPerSession ?? 3;\n if (this.adsThisSession >= maxSession) return false;\n const hourMs = 60 * 60 * 1000;\n const currentHourStart = Math.floor(now / hourMs) * hourMs;\n if (currentHourStart !== this.lastHourStart) {\n this.lastHourStart = currentHourStart;\n this.adsThisHour = 0;\n }\n const maxHour = frequency.maxAdsPerHour ?? 6;\n if (this.adsThisHour >= maxHour) return false;\n return true;\n }\n\n private recordAdShown(): void {\n this.lastAdTime = Date.now();\n this.adsThisSession += 1;\n this.adsThisHour += 1;\n }\n\n /**\n * Config-driven entry point: show ad and/or game based on dashboard config, then run processing.\n */\n async showAd<T>(\n processingFn: () => Promise<T>,\n options: {\n estimatedDuration?: number;\n batchId?: string;\n message?: string;\n overrideConfig?: Partial<WaitlessConfig>;\n } = {}\n ): Promise<T> {\n if (!processingFn || typeof processingFn !== 'function') {\n throw new Error('Processing function is required and must be a function');\n }\n await this.ensureConfigLoaded();\n const base = this.config ?? this.getDefaultConfig();\n const merged: WaitlessConfig = {\n ...base,\n strategy: { ...base.strategy, ...options.overrideConfig?.strategy },\n frequency: { ...base.frequency, ...options.overrideConfig?.frequency },\n duration: { ...base.duration, ...options.overrideConfig?.duration },\n batch: { ...base.batch, ...options.overrideConfig?.batch },\n fallback: { ...base.fallback, ...options.overrideConfig?.fallback },\n analytics: { ...base.analytics, ...options.overrideConfig?.analytics }\n };\n const batch = merged.batch ?? {};\n const frequency = merged.frequency ?? {};\n const strategy = merged.strategy ?? {};\n const behavior = strategy.behavior ?? 'auto';\n const duration = merged.duration ?? {};\n const message = options.message ?? 'Loading...';\n\n if (options.batchId && batch.enabled && batch.showAdOnce && this.batchIdsSeen.has(options.batchId)) {\n return this.showProcessing(processingFn, 'spinner', message);\n }\n if (!this.shouldShowAd(frequency)) {\n return this.showProcessing(processingFn, 'spinner', message);\n }\n\n const shortThreshold = duration.shortThreshold ?? 10;\n const longThreshold = duration.longThreshold ?? 60;\n const estimatedDuration = options.estimatedDuration ?? 0;\n const enableGames = duration.enableGames !== false;\n let mode: 'ad-only' | 'ad-plus-game' | 'game-only' = 'ad-only';\n if (behavior === 'game-only' || (enableGames && estimatedDuration > longThreshold)) {\n mode = 'game-only';\n } else if (enableGames && estimatedDuration > shortThreshold && estimatedDuration <= longThreshold) {\n mode = 'ad-plus-game';\n }\n\n if (options.batchId && batch.enabled && batch.showAdOnce) {\n this.batchIdsSeen.add(options.batchId);\n }\n\n if (mode === 'game-only') {\n return this.showGame(processingFn, { message });\n }\n\n const validatedOptions = validateOptions({ container: undefined, message });\n const session = await this.createSession(validatedOptions);\n const { container, overlay } = this.initializeGameUI(validatedOptions);\n const adMaxDuration = duration.adMaxDuration ?? 15;\n\n try {\n if (session.sessionId) {\n await this.playAdInContainer(container, {\n adTagUrl: this.defaultAdTagUrl,\n maxDuration: adMaxDuration,\n sessionId: session.sessionId\n });\n this.recordAdShown();\n }\n if (mode === 'ad-plus-game') {\n const gameInstance = this.startGame(validatedOptions);\n const result = await processingFn();\n this.endGame(session.sessionId);\n this.cleanup(overlay, gameInstance);\n return result;\n }\n container.innerHTML = '';\n const spinner = document.createElement('div');\n spinner.style.cssText =\n 'width:40px;height:40px;border:3px solid rgba(255,255,255,0.3);border-top-color:#fff;border-radius:50%;animation:waitless-spin 0.8s linear infinite;margin:auto;';\n const text = document.createElement('div');\n text.textContent = message;\n text.style.cssText = 'color:#fff;font-size:18px;margin-top:12px;text-align:center;';\n container.style.display = 'flex';\n container.style.flexDirection = 'column';\n container.style.alignItems = 'center';\n container.style.justifyContent = 'center';\n container.appendChild(spinner);\n container.appendChild(text);\n if (!document.getElementById('waitless-spinner-style')) {\n const style = document.createElement('style');\n style.id = 'waitless-spinner-style';\n style.textContent = '@keyframes waitless-spin { to { transform: rotate(360deg); } }';\n document.head.appendChild(style);\n }\n const result = await processingFn();\n this.endGame(session.sessionId);\n this.cleanup(overlay, null);\n return result;\n } catch (err) {\n this.endGame(session.sessionId);\n this.cleanup(overlay, null);\n throw err;\n }\n }\n\n /**\n * Show a game while executing a long-running function\n * @param processingFn The function to execute while showing the game\n * @param options Game configuration options\n * @returns Promise with the result of the processing function\n */\n async showGame<T>(processingFn: () => Promise<T>, options: GameOptions = {}): Promise<T> {\n if (!processingFn || typeof processingFn !== 'function') {\n throw new Error('Processing function is required and must be a function');\n }\n\n const showAds = options.showAds !== false && this.apiKey !== 'demo';\n const adPlacement = options.adPlacement || 'pre-game';\n const validatedOptions = validateOptions(options);\n\n const session = await this.createSession(validatedOptions);\n const { container, overlay } = this.initializeGameUI(validatedOptions);\n let gameInstance: any = null;\n\n try {\n if (showAds && session.sessionId && (adPlacement === 'pre-game' || adPlacement === 'both')) {\n await this.playAdInContainer(container, {\n adTagUrl: options.adTagUrl || this.defaultAdTagUrl,\n maxDuration: options.adDuration || 15,\n sessionId: session.sessionId\n });\n }\n\n gameInstance = this.startGame(validatedOptions);\n const result = await processingFn();\n\n if (showAds && session.sessionId && (adPlacement === 'post-game' || adPlacement === 'both')) {\n await this.playAdInContainer(container, {\n adTagUrl: options.adTagUrl || this.defaultAdTagUrl,\n maxDuration: options.adDuration || 15,\n sessionId: session.sessionId\n });\n }\n\n this.endGame(session.sessionId);\n this.cleanup(overlay, gameInstance);\n return result;\n } catch (error) {\n this.endGame(session.sessionId);\n this.cleanup(overlay, gameInstance || this.gameInstance);\n throw error;\n }\n }\n\n /**\n * Create a new game session with the API\n * @param options Game options\n * @returns Session id and config (null for demo/offline)\n */\n private async createSession(options: GameOptions): Promise<{ sessionId: string | null; config?: Record<string, any> | null }> {\n if (this.apiKey === 'demo') {\n this.sessionId = null;\n this.lastBackendConfig = null;\n return { sessionId: null, config: null };\n }\n try {\n const response = await fetch(`${this.baseUrl}/sessions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey\n },\n body: JSON.stringify({\n game: options.game,\n theme: options.theme,\n message: options.message\n })\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create game session: ${response.statusText}`);\n }\n\n const data = await response.json();\n this.sessionId = data.sessionId;\n this.lastBackendConfig = data.config && typeof data.config === 'object' ? data.config : null;\n return { sessionId: this.sessionId, config: this.lastBackendConfig };\n } catch (error) {\n console.error('Error creating WaitlessAPI session:', error);\n this.sessionId = null;\n this.lastBackendConfig = null;\n return { sessionId: null, config: null };\n }\n }\n\n /**\n * Initialize the game UI container\n * @param options Game options\n * @returns container and overlay (overlay is non-null when we created the full-screen div)\n */\n private initializeGameUI(options: GameOptions): { container: HTMLElement; overlay: HTMLElement | null } {\n let overlay: HTMLElement | null = null;\n if (options.container) {\n if (typeof options.container === 'string') {\n this.container = document.querySelector(options.container);\n if (!this.container) {\n throw new Error(`Container element not found: ${options.container}`);\n }\n } else {\n this.container = options.container;\n }\n } else {\n this.container = document.createElement('div');\n this.container.id = 'waitless-game-container';\n this.container.style.position = 'fixed';\n this.container.style.top = '0';\n this.container.style.left = '0';\n this.container.style.width = '100%';\n this.container.style.height = '100%';\n this.container.style.zIndex = '9999';\n document.body.appendChild(this.container);\n overlay = this.container;\n }\n\n if (options.width) {\n this.container.style.width = `${options.width}px`;\n }\n if (options.height) {\n this.container.style.height = `${options.height}px`;\n }\n\n const messageElement = document.createElement('div');\n messageElement.id = 'waitless-message';\n messageElement.textContent = options.message || 'Loading...';\n messageElement.style.position = 'absolute';\n messageElement.style.bottom = '20px';\n messageElement.style.left = '0';\n messageElement.style.width = '100%';\n messageElement.style.textAlign = 'center';\n messageElement.style.color = '#ffffff';\n messageElement.style.fontSize = '18px';\n messageElement.style.fontFamily = 'Arial, sans-serif';\n messageElement.style.padding = '10px';\n this.container.appendChild(messageElement);\n\n return { container: this.container, overlay };\n }\n\n /**\n * Start the game\n * @param options Game options\n * @returns The game instance\n */\n private startGame(options: GameOptions): any {\n if (!this.container) {\n return null;\n }\n\n const mergedConfig: Record<string, any> = {\n container: this.container,\n theme: options.theme || 'default',\n onScore: options.onScore\n };\n if (options.width != null) mergedConfig.width = options.width;\n if (options.height != null) mergedConfig.height = options.height;\n if (this.lastBackendConfig) {\n Object.assign(mergedConfig, this.lastBackendConfig);\n }\n\n this.gameInstance = loadGame(options.game || 'tetris', mergedConfig as GameConfig);\n\n if (this.gameInstance && typeof this.gameInstance.start === 'function') {\n this.gameInstance.start();\n }\n\n this.isPlaying = true;\n\n if (options.onStart && typeof options.onStart === 'function') {\n options.onStart();\n }\n\n return this.gameInstance;\n }\n\n private async playAdInContainer(\n container: HTMLElement,\n config: { adTagUrl: string; maxDuration: number; sessionId: string | null }\n ): Promise<void> {\n if (config.sessionId === null) {\n return;\n }\n\n const adPlayer = new AdPlayer(container);\n const adStartTime = Date.now();\n\n try {\n await adPlayer.playAd({\n adTagUrl: config.adTagUrl,\n maxDuration: config.maxDuration,\n onAdStarted: () => {\n this.trackAdEvent(config.sessionId!, 'ad_started');\n },\n onAdComplete: () => {\n const duration = (Date.now() - adStartTime) / 1000;\n this.trackAdEvent(config.sessionId!, 'ad_completed', { duration });\n },\n onAdSkipped: () => {\n const duration = (Date.now() - adStartTime) / 1000;\n this.trackAdEvent(config.sessionId!, 'ad_skipped', { duration });\n },\n onAdError: (error) => {\n this.trackAdEvent(config.sessionId!, 'ad_error', { error: String(error) });\n }\n });\n } catch (error) {\n console.warn('Ad loading failed, continuing:', error);\n } finally {\n adPlayer.destroy();\n }\n }\n\n private async trackAdEvent(sessionId: string, event: string, data?: any): Promise<void> {\n try {\n await fetch(`${this.baseUrl}/sessions/${sessionId}/ad-event`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey\n },\n body: JSON.stringify({\n event,\n timestamp: Date.now(),\n ...data\n })\n });\n } catch (error) {\n console.warn('Failed to track ad event:', error);\n }\n }\n\n private cleanup(overlay: HTMLElement | null, gameInstance: any): void {\n if (overlay && overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n this.container = null;\n this.gameInstance = null;\n this.isPlaying = false;\n }\n\n /**\n * End the game and send session complete (overlay removal is done in cleanup)\n */\n private endGame(sessionId?: string | null): void {\n if (!this.isPlaying && !this.gameInstance) {\n return;\n }\n\n const score = this.gameInstance && typeof this.gameInstance.getScore === 'function'\n ? this.gameInstance.getScore()\n : (this.gameInstance?.score ?? 0);\n\n if (this.gameInstance && typeof this.gameInstance.destroy === 'function') {\n this.gameInstance.destroy();\n }\n\n this.isPlaying = false;\n this.gameInstance = null;\n this.container = null;\n\n const id = sessionId !== undefined ? sessionId : this.sessionId;\n if (id) {\n this.completeSession(score, id);\n }\n this.sessionId = null;\n }\n\n private async completeSession(score: number, sessionId: string): Promise<void> {\n try {\n await fetch(`${this.baseUrl}/sessions/${sessionId}/complete`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey\n },\n body: JSON.stringify({ duration: 0, score })\n });\n } catch (error) {\n console.error('Error completing game session:', error);\n }\n }\n} ","import { GameType } from '../core';\nimport TetrisGame from './tetris';\nimport SnakeGame from './snake';\nimport BreakoutGame from './breakout';\nimport { GameConfig } from './base';\n\nexport { GameConfig } from './base';\nexport { BaseGame } from './base';\n\n/**\n * Load a game instance\n * @param gameType Type of game to load\n * @param config Game configuration\n * @returns Game instance\n */\nexport function loadGame(gameType: GameType, config: GameConfig): any {\n switch (gameType) {\n case 'tetris':\n return new TetrisGame(config);\n case 'snake':\n return new SnakeGame(config);\n case 'breakout':\n return new BreakoutGame(config);\n default:\n // TypeScript should prevent this, but just in case\n return new TetrisGame(config);\n }\n} "],"names":["BaseGame","constructor","config","this","isRunning","score","container","theme","onScoreCallback","onScore","updateScore","points","getScore","isActive","TetrisGame","super","grid","currentPiece","nextPiece","animationFrame","lastTime","dropInterval","dropCounter","shapes","colors","handleKeyDown","e","key","movePiece","dropPiece","rotatePiece","checkCollision","pos","y","mergePiece","checkLines","createPiece","blockSize","width","height","cols","Math","floor","rows","speed","scoring","singleLine","doubleLine","tripleLine","tetris","max","canvas","document","createElement","style","display","margin","border","appendChild","ctx","getContext","Error","resetGrid","setupControls","start","update","pause","cancelAnimationFrame","resume","destroy","window","removeEventListener","parentNode","removeChild","time","deltaTime","draw","requestAnimationFrame","bind","fillStyle","fillRect","drawGrid","drawPiece","x","value","strokeStyle","strokeRect","piece","shape","length","Array","fill","map","shapeIndex","random","nextShapeIndex","gridX","gridY","linesCleared","every","splice","unshift","pts","_a","dir","rotated","row","push","offset","addEventListener","THEME_COLORS","default","primary","secondary","accent","text","cyberpunk","minimal","corporate","SnakeGame","snake","food","direction","nextDirection","moveInterval","moveCounter","highScore","touchStartX","touchStartY","current","preventDefault","handleTouchStart","touches","clientX","clientY","handleTouchEnd","changedTouches","dx","dy","abs","gridSize","foodValue","gridWidth","gridHeight","cellSize","min","getColors","resetGame","moveSnake","globalAlpha","i","beginPath","moveTo","lineTo","stroke","j","seg","isHead","font","fillText","cx","cy","spawnFood","empty","some","s","head","nx","ny","gameOver","shift","passive","BreakoutGame","bricks","ballLaunched","lives","level","paused","paddleHeight","ballRadius","brickPadding","brickOffsetTop","handleMouseMove","rect","getBoundingClientRect","scaleX","relativeX","left","paddle","handleTouchMove","handleClick","launchBall","paddleWidth","brickRows","brickColumns","baseBallSpeed","ballSpeed","ball","radius","updateGameState","initBricks","rowColors","brickW","r","c","visible","color","hitPos","brick","filter","b","forEach","arc","PI","textAlign","validateOptions","options","validatedOptions","game","includes","console","warn","message","String","AdPlayer","loadingOverlay","adBadge","adDisplayContainer","adsLoader","adsManager","videoElement","adContainer","setupElements","cssText","w","offsetWidth","h","offsetHeight","textContent","showLoadingOverlay","setAttribute","spinner","removeLoadingOverlay","showErrorOverlay","thenRun","overlay","btn","run","setTimeout","playAd","Promise","resolve","onError","cleanup","google","ima","initializeAd","loadIMAScript","then","catch","onAdError","call","reject","script","src","async","onload","onerror","AdDisplayContainer","AdsLoader","AdsManagerLoadedEvent","Type","ADS_MANAGER_LOADED","event","onAdsManagerLoaded","AdErrorEvent","AD_ERROR","getError","adsRequest","AdsRequest","adTagUrl","linearAdSlotWidth","linearAdSlotHeight","nonLinearAdSlotWidth","nonLinearAdSlotHeight","initialize","requestAds","adsRenderingSettings","AdsRenderingSettings","restoreCustomPlaybackStateOnAdBreakComplete","getAdsManager","AdEvent","CONTENT_PAUSE_REQUESTED","onAdStarted","CONTENT_RESUME_REQUESTED","onAdComplete","ALL_ADS_COMPLETED","SKIPPED","onAdSkipped","init","ViewMode","NORMAL","error","_","CONFIG_CACHE_KEY_PREFIX","WaitlessAPI","apiKey","baseUrlOrOptions","sessionId","gameInstance","isPlaying","lastBackendConfig","configLoaded","configPromise","batchIdsSeen","Set","lastAdTime","adsThisSession","adsThisHour","lastHourStart","baseUrl","apiBaseUrl","defaultAdTagUrl","loadConfig","url","Image","getDefaultConfig","strategy","preset","behavior","frequency","minInterval","maxAdsPerSession","maxAdsPerHour","duration","shortThreshold","longThreshold","adMaxDuration","enableGames","batch","enabled","showAdOnce","fallback","type","showMessage","analytics","trackEvents","enableABTesting","getCachedConfig","raw","localStorage","getItem","timestamp","JSON","parse","Date","now","cacheConfig","setItem","stringify","cached","encodeURIComponent","res","fetch","ok","data","json","ensureConfigLoaded","refreshConfig","removeItem","getConfig","showProcessing","processingFn","getElementById","id","body","remove","shouldShowAd","maxSession","_b","hourMs","currentHourStart","maxHour","_c","recordAdShown","showAd","base","merged","overrideConfig","_d","_e","_f","_g","_h","_j","_l","_k","_m","_o","batchId","has","_p","_q","estimatedDuration","_r","mode","add","showGame","undefined","session","createSession","initializeGameUI","_s","playAdInContainer","maxDuration","startGame","result","endGame","innerHTML","flexDirection","alignItems","justifyContent","err","showAds","adPlacement","adDuration","response","method","headers","statusText","querySelector","position","top","zIndex","messageElement","bottom","fontSize","fontFamily","padding","mergedConfig","Object","assign","gameType","loadGame","onStart","adPlayer","adStartTime","trackAdEvent","completeSession"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { GameOptions } from '../core';
2
+ /**
3
+ * Validate and normalize game options
4
+ * @param options User-provided game options
5
+ * @returns Validated game options
6
+ */
7
+ export declare function validateOptions(options: GameOptions): GameOptions;
8
+ /**
9
+ * Preload common assets used by games
10
+ */
11
+ export declare function preloadAssets(): void;
12
+ /**
13
+ * Detect browser capabilities and limitations
14
+ * @returns Object with browser capability information
15
+ */
16
+ export declare function detectBrowserCapabilities(): {
17
+ touchEnabled: boolean;
18
+ webGLSupport: boolean;
19
+ screenSize: {
20
+ width: number;
21
+ height: number;
22
+ };
23
+ };
24
+ /**
25
+ * Create a throttled function
26
+ * @param callback Function to throttle
27
+ * @param delay Delay in milliseconds
28
+ * @returns Throttled function
29
+ */
30
+ export declare function throttle<T extends (...args: any[]) => any>(callback: T, delay: number): (...args: Parameters<T>) => void;
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "waitless-api",
3
+ "version": "0.1.0",
4
+ "description": "WaitlessAPI SDK for interactive loading games",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "dev": "rollup -c -w",
13
+ "build": "rollup -c",
14
+ "lint": "eslint src/**/*.ts",
15
+ "test": "jest",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "loading",
20
+ "games",
21
+ "tetris",
22
+ "snake",
23
+ "breakout",
24
+ "api"
25
+ ],
26
+ "author": "",
27
+ "license": "MIT",
28
+ "dependencies": {},
29
+ "devDependencies": {
30
+ "@rollup/plugin-commonjs": "^22.0.0",
31
+ "@rollup/plugin-node-resolve": "^13.3.0",
32
+ "@rollup/plugin-typescript": "^8.3.3",
33
+ "@types/jest": "^28.1.1",
34
+ "eslint": "^8.17.0",
35
+ "jest": "^28.1.1",
36
+ "rollup": "^2.75.6",
37
+ "rollup-plugin-terser": "^7.0.2",
38
+ "ts-jest": "^28.0.4",
39
+ "tslib": "^2.4.0",
40
+ "typescript": "^4.7.3"
41
+ }
42
+ }