Balance Master - Physics Puzzle

A fun game created with AI

🤖 System_default ⚡ 103.9s 🎯 12,923 tokens $0.1503

Created by BraveArtist0557 • November 22, 2025

View Game Code
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
    <title>Balance Master - Physics Puzzle</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            -webkit-tap-highlight-color: transparent;
        }
        body {
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            font-family: 'Arial', sans-serif;
            overflow: hidden;
            touch-action: manipulation;
        }
        #gameContainer {
            position: relative;
            max-width: 100vw;
            max-height: 100vh;
        }
        canvas {
            border: 3px solid #fff;
            box-shadow: 0 10px 30px rgba(0,0,0,0.3);
            display: block;
            touch-action: none;
            background: #1a1a2e;
        }
        #ui {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-size: 18px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
            pointer-events: none;
            z-index: 10;
        }
        #controls {
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            gap: 10px;
            z-index: 10;
        }
        button {
            padding: 12px 24px;
            font-size: 16px;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-weight: bold;
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
            touch-action: manipulation;
        }
        button:hover {
            background: #45a049;
        }
        button:active {
            transform: translateY(2px);
        }
        .menu-btn {
            background: #2196F3;
        }
        .menu-btn:hover {
            background: #0b7dda;
        }
        .editor-btn {
            background: #FF9800;
        }
        .editor-btn:hover {
            background: #e68900;
        }
        #menu {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(26, 26, 46, 0.95);
            padding: 30px;
            border-radius: 15px;
            text-align: center;
            color: white;
            z-index: 100;
            min-width: 300px;
        }
        #menu h2 {
            margin-bottom: 20px;
            font-size: 28px;
        }
        #menu button {
            margin: 10px;
            min-width: 200px;
        }
        .hidden {
            display: none !important;
        }
    

        /* Mobile optimization CSS */

body {
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    background: #000;
    font-family: Arial, sans-serif;
    overflow: hidden; /* Prevent scrolling on mobile */

    /* Safe area insets for iPhone notch/home indicator */
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);

    /* Prevent text selection and long-press menus on mobile */
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;

    /* Disable tap highlight on mobile */
    -webkit-tap-highlight-color: transparent;

    /* Optimize for touch */
    touch-action: manipulation;
}

#game {
    border: 2px solid #fff;
    max-width: 100vw;
    max-height: 100vh;
    display: block;
    touch-action: none; /* Prevent default touch behaviors on canvas */
}

/* UI elements should be positioned safely */
.game-ui {
    position: absolute;
    color: #fff;
    font-size: clamp(14px, 3vw, 24px); /* Responsive font size */
    z-index: 10;
    pointer-events: none; /* UI doesn't interfere with touch controls */
}

.score {
    top: max(10px, env(safe-area-inset-top) + 10px);
    left: max(10px, env(safe-area-inset-left) + 10px);
}

.lives {
    top: max(10px, env(safe-area-inset-top) + 10px);
    right: max(10px, env(safe-area-inset-right) + 10px);
}

</style>
</head>
<body>
    <div id="gameContainer">
        <canvas id="game"></canvas>
        <div id="ui">
            <div id="levelInfo">Level: 1</div>
            <div id="timeInfo">Time: 30s</div>
            <div id="balanceInfo">Balance: 0%</div>
        </div>
        <div id="controls">
            <button id="resetBtn" class="menu-btn">Reset</button>
            <button id="menuBtn" class="menu-btn">Menu</button>
        </div>
        <div id="menu" class="hidden">
            <h2>Balance Master</h2>
            <button id="playBtn">Play Levels</button>
            <button id="editorBtn" class="editor-btn">Level Editor</button>
            <button id="loadBtn" class="editor-btn">Load Custom Level</button>
        </div>
    </div>
    <script>
        window.addEventListener('load', function() {
            try {
                const canvas = document.getElementById('game');
                if (!canvas) { alert('Canvas not found'); return; }
                const ctx = canvas.getContext('2d');
                if (!ctx) { alert('Canvas context failed'); return; }

                // Responsive canvas setup
                function resizeCanvas() {
                    const maxWidth = Math.min(window.innerWidth - 20, 900);
                    const maxHeight = Math.min(window.innerHeight - 120, 600);
                    const size = Math.min(maxWidth, maxHeight * 1.5);
                    canvas.width = size;
                    canvas.height = size / 1.5;
                }
                resizeCanvas();
                window.addEventListener('resize', resizeCanvas);

                // Game state
                let gameState = 'menu';
                let currentLevel = 0;
                let gameTime = 30;
                let lastSecond = Date.now();
                let balancePercentage = 0;
                let selectedObject = null;
                let dragOffset = { x: 0, y: 0 };
                let isEditorMode = false;
                let editorObjects = [];
                let editorSelectedType = 'weight';

                // Physics constants
                const GRAVITY = 0.3;
                const BALANCE_THRESHOLD = 10;
                const FULCRUM_HEIGHT = 20;

                // Game objects
                class Weight {
                    constructor(x, y, mass, color = '#FFD700') {
                        this.x = x;
                        this.y = y;
                        this.mass = mass;
                        this.size = 20 + mass * 5;
                        this.color = color;
                        this.vx = 0;
                        this.vy = 0;
                        this.isDragging = false;
                        this.onPlatform = false;
                    }

                    draw() {
                        ctx.fillStyle = this.color;
                        ctx.beginPath();
                        ctx.arc(this.x, this.y, this.size / 2, 0, Math.PI * 2);
                        ctx.fill();
                        ctx.strokeStyle = '#fff';
                        ctx.lineWidth = 2;
                        ctx.stroke();
                        
                        ctx.fillStyle = '#000';
                        ctx.font = 'bold 14px Arial';
                        ctx.textAlign = 'center';
                        ctx.textBaseline = 'middle';
                        ctx.fillText(this.mass, this.x, this.y);
                    }

                    contains(px, py) {
                        const dx = px - this.x;
                        const dy = py - this.y;
                        return dx * dx + dy * dy <= (this.size / 2) * (this.size / 2);
                    }
                }

                class Scale {
                    constructor(x, y, width, leftSide = true) {
                        this.x = x;
                        this.y = y;
                        this.width = width;
                        this.leftSide = leftSide;
                        this.angle = 0;
                        this.targetAngle = 0;
                    }

                    calculateTorque(weights) {
                        let leftTorque = 0;
                        let rightTorque = 0;

                        weights.forEach(weight => {
                            if (this.isOnPlatform(weight)) {
                                const distance = weight.x - this.x;
                                const torque = weight.mass * distance;
                                if (distance < 0) {
                                    leftTorque += Math.abs(torque);
                                } else {
                                    rightTorque += Math.abs(torque);
                                }
                            }
                        });

                        const netTorque = rightTorque - leftTorque;
                        this.targetAngle = Math.max(-0.3, Math.min(0.3, netTorque / 500));
                        this.angle += (this.targetAngle - this.angle) * 0.1;

                        return { leftTorque, rightTorque, netTorque };
                    }

                    isOnPlatform(weight) {
                        const platformY = this.y + Math.sin(this.angle) * (weight.x - this.x);
                        return Math.abs(weight.y - platformY) < 5 && 
                               weight.x > this.x - this.width / 2 && 
                               weight.x < this.x + this.width / 2;
                    }

                    draw() {
                        ctx.save();
                        ctx.translate(this.x, this.y);
                        
                        // Fulcrum
                        ctx.fillStyle = '#8B4513';
                        ctx.beginPath();
                        ctx.moveTo(-15, 0);
                        ctx.lineTo(15, 0);
                        ctx.lineTo(0, FULCRUM_HEIGHT);
                        ctx.closePath();
                        ctx.fill();

                        // Platform
                        ctx.rotate(this.angle);
                        ctx.fillStyle = '#CD853F';
                        ctx.fillRect(-this.width / 2, -10, this.width, 20);
                        ctx.strokeStyle = '#8B4513';
                        ctx.lineWidth = 3;
                        ctx.strokeRect(-this.width / 2, -10, this.width, 20);

                        ctx.restore();
                    }
                }

                class MovingPlatform {
                    constructor(x, y, width, speed, rangeX) {
                        this.x = x;
                        this.y = y;
                        this.startX = x;
                        this.width = width;
                        this.height = 15;
                        this.speed = speed;
                        this.rangeX = rangeX;
                        this.direction = 1;
                    }

                    update() {
                        this.x += this.speed * this.direction;
                        if (this.x > this.startX + this.rangeX || this.x < this.startX - this.rangeX) {
                            this.direction *= -1;
                        }
                    }

                    draw() {
                        ctx.fillStyle = '#4CAF50';
                        ctx.fillRect(this.x - this.width / 2, this.y, this.width, this.height);
                        ctx.strokeStyle = '#2E7D32';
                        ctx.lineWidth = 2;
                        ctx.strokeRect(this.x - this.width / 2, this.y, this.width, this.height);
                    }

                    isOn(weight) {
                        return weight.x > this.x - this.width / 2 && 
                               weight.x < this.x + this.width / 2 && 
                               Math.abs(weight.y - this.y) < 5;
                    }
                }

                // Level definitions
                const levels = [
                    {
                        name: "Tutorial",
                        time: 60,
                        scale: { x: 400, y: 300, width: 300 },
                        weights: [
                            { x: 100, y: 100, mass: 3, color: '#FFD700' },
                            { x: 200, y: 100, mass: 3, color: '#FFD700' }
                        ],
                        platforms: [],
                        goal: "Balance the scale!"
                    },
                    {
                        name: "Unequal Weights",
                        time: 45,
                        scale: { x: 400, y: 350, width: 300 },
                        weights: [
                            { x: 150, y: 100, mass: 2, color: '#87CEEB' },
                            { x: 250, y: 100, mass: 4, color: '#FF6347' },
                            { x: 350, y: 100, mass: 2, color: '#87CEEB' }
                        ],
                        platforms: [],
                        goal: "Use position to balance!"
                    },
                    {
                        name: "Moving Platform",
                        time: 50,
                        scale: { x: 400, y: 400, width: 300 },
                        weights: [
                            { x: 100, y: 50, mass: 3, color: '#FFD700' },
                            { x: 700, y: 50, mass: 3, color: '#FFD700' }
                        ],
                        platforms: [
                            { x: 400, y: 200, width: 80, speed: 2, rangeX: 150 }
                        ],
                        goal: "Catch weights on platform!"
                    },
                    {
                        name: "Triple Threat",
                        time: 40,
                        scale: { x: 400, y: 380, width: 350 },
                        weights: [
                            { x: 100, y: 100, mass: 5, color: '#FF6347' },
                            { x: 300, y: 100, mass: 2, color: '#87CEEB' },
                            { x: 500, y: 100, mass: 2, color: '#87CEEB' },
                            { x: 700, y: 100, mass: 1, color: '#98FB98' }
                        ],
                        platforms: [],
                        goal: "Perfect balance!"
                    },
                    {
                        name: "Speed Challenge",
                        time: 30,
                        scale: { x: 400, y: 350, width: 300 },
                        weights: [
                            { x: 100, y: 100, mass: 4, color: '#FF6347' },
                            { x: 200, y: 100, mass: 2, color: '#87CEEB' },
                            { x: 600, y: 100, mass: 2, color: '#87CEEB' }
                        ],
                        platforms: [
                            { x: 400, y: 150, width: 60, speed: 3, rangeX: 200 }
                        ],
                        goal: "Quick balance!"
                    },
                    {
                        name: "Precision",
                        time: 50,
                        scale: { x: 450, y: 400, width: 400 },
                        weights: [
                            { x: 100, y: 100, mass: 1, color: '#98FB98' },
                            { x: 200, y: 100, mass: 1, color: '#98FB98' },
                            { x: 300, y: 100, mass: 1, color: '#98FB98' },
                            { x: 600, y: 100, mass: 3, color: '#FFD700' }
                        ],
                        platforms: [],
                        goal: "Precise placement!"
                    },
                    {
                        name: "Double Platform",
                        time: 45,
                        scale: { x: 400, y: 450, width: 300 },
                        weights: [
                            { x: 100, y: 50, mass: 3, color: '#FFD700' },
                            { x: 700, y: 50, mass: 3, color: '#FFD700' }
                        ],
                        platforms: [
                            { x: 250, y: 200, width: 70, speed: 2, rangeX: 100 },
                            { x: 550, y: 250, width: 70, speed: -2.5, rangeX: 100 }
                        ],
                        goal: "Coordinate platforms!"
                    },
                    {
                        name: "Heavy Lifting",
                        time: 40,
                        scale: { x: 400, y: 380, width: 350 },
                        weights: [
                            { x: 150, y: 100, mass: 6, color: '#8B008B' },
                            { x: 350, y: 100, mass: 2, color: '#87CEEB' },
                            { x: 550, y: 100, mass: 2, color: '#87CEEB' },
                            { x: 650, y: 100, mass: 2, color: '#87CEEB' }
                        ],
                        platforms: [],
                        goal: "Balance the heavy one!"
                    },
                    {
                        name: "Chaos",
                        time: 35,
                        scale: { x: 400, y: 420, width: 350 },
                        weights: [
                            { x: 100, y: 80, mass: 5, color: '#FF6347' },
                            { x: 250, y: 80, mass: 1, color: '#98FB98' },
                            { x: 550, y: 80, mass: 3, color: '#FFD700' },
                            { x: 700, y: 80, mass: 1, color: '#98FB98' }
                        ],
                        platforms: [
                            { x: 400, y: 180, width: 60, speed: 3.5, rangeX: 180 }
                        ],
                        goal: "Master the chaos!"
                    },
                    {
                        name: "Final Challenge",
                        time: 30,
                        scale: { x: 400, y: 450, width: 400 },
                        weights: [
                            { x: 100, y: 60, mass: 4, color: '#FF6347' },
                            { x: 250, y: 60, mass: 2, color: '#87CEEB' },
                            { x: 550, y: 60, mass: 2, color: '#87CEEB' },
                            { x: 700, y: 60, mass: 4, color: '#FF6347' }
                        ],
                        platforms: [
                            { x: 200, y: 200, width: 60, speed: 2.5, rangeX: 120 },
                            { x: 600, y: 250, width: 60, speed: -3, rangeX: 120 }
                        ],
                        goal: "Ultimate balance!"
                    }
                ];

                let scale, weights, platforms;

                function loadLevel(levelIndex) {
                    const level = levels[levelIndex];
                    if (!level) return false;

                    scale = new Scale(level.scale.x, level.scale.y, level.scale.width);
                    weights = level.weights.map(w => new Weight(w.x, w.y, w.mass, w.color));
                    platforms = level.platforms.map(p => new MovingPlatform(p.x, p.y, p.width, p.speed, p.rangeX));
                    gameTime = level.time;
                    lastSecond = Date.now();
                    balancePercentage = 0;

                    document.getElementById('levelInfo').textContent = `Level: ${levelIndex + 1} - ${level.name}`;
                    return true;
                }

                // Input handling
                const keys = {};
                window.addEventListener('keydown', (e) => {
                    keys[e.key] = true;
                    e.preventDefault();
                });
                window.addEventListener('keyup', (e) => {
                    keys[e.key] = false;
                });

                // Mouse/Touch handling
                function getMousePos(e) {
                    const rect = canvas.getBoundingClientRect();
                    const scaleX = canvas.width / rect.width;
                    const scaleY = canvas.height / rect.height;
                    const clientX = e.clientX || (e.touches && e.touches[0].clientX);
                    const clientY = e.clientY || (e.touches && e.touches[0].clientY);
                    return {
                        x: (clientX - rect.left) * scaleX,
                        y: (clientY - rect.top) * scaleY
                    };
                }

                canvas.addEventListener('mousedown', handleStart);
                canvas.addEventListener('touchstart', handleStart, { passive: false });
                canvas.addEventListener('mousemove', handleMove);
                canvas.addEventListener('touchmove', handleMove, { passive: false });
                canvas.addEventListener('mouseup', handleEnd);
                canvas.addEventListener('touchend', handleEnd);

                function handleStart(e) {
                    e.preventDefault();
                    const pos = getMousePos(e);
                    
                    if (isEditorMode) {
                        // Editor mode - add object
                        if (editorSelectedType === 'weight') {
                            editorObjects.push({
                                type: 'weight',
                                x: pos.x,
                                y: pos.y,
                                mass: 3,
                                color: '#FFD700'
                            });
                        } else if (editorSelectedType === 'scale') {
                            editorObjects.push({
                                type: 'scale',
                                x: pos.x,
                                y: pos.y,
                                width: 300
                            });
                        } else if (editorSelectedType === 'platform') {
                            editorObjects.push({
                                type: 'platform',
                                x: pos.x,
                                y: pos.y,
                                width: 80,
                                speed: 2,
                                rangeX: 100
                            });
                        }
                        return;
                    }

                    for (let i = weights.length - 1; i >= 0; i--) {
                        if (weights[i].contains(pos.x, pos.y)) {
                            selectedObject = weights[i];
                            selectedObject.isDragging = true;
                            dragOffset.x = pos.x - selectedObject.x;
                            dragOffset.y = pos.y - selectedObject.y;
                            break;
                        }
                    }
                }

                function handleMove(e) {
                    e.preventDefault();
                    if (selectedObject && selectedObject.isDragging) {
                        const pos = getMousePos(e);
                        selectedObject.x = pos.x - dragOffset.x;
                        selectedObject.y = pos.y - dragOffset.y;
                        selectedObject.vx = 0;
                        selectedObject.vy = 0;
                    }
                }

                function handleEnd(e) {
                    e.preventDefault();
                    if (selectedObject) {
                        selectedObject.isDragging = false;
                        selectedObject = null;
                    }
                }

                // UI Controls
                document.getElementById('resetBtn').addEventListener('click', () => {
                    if (gameState === 'playing') {
                        loadLevel(currentLevel);
                    }
                });

                document.getElementById('menuBtn').addEventListener('click', () => {
                    gameState = 'menu';
                    document.getElementById('menu').classList.remove('hidden');
                });

                document.getElementById('playBtn').addEventListener('click', () => {
                    gameState = 'playing';
                    isEditorMode = false;
                    currentLevel = 0;
                    loadLevel(currentLevel);
                    document.getElementById('menu').classList.add('hidden');
                });

                document.getElementById('editorBtn').addEventListener('click', () => {
                    gameState = 'editor';
                    isEditorMode = true;
                    editorObjects = [];
                    document.getElementById('menu').classList.add('hidden');
                });

                document.getElementById('loadBtn').addEventListener('click', () => {
                    const levelData = prompt('Paste custom level code:');
                    if (levelData) {
                        try {
                            const customLevel = JSON.parse(atob(levelData));
                            gameState = 'playing';
                            isEditorMode = false;
                            scale = new Scale(customLevel.scale.x, customLevel.scale.y, customLevel.scale.width);
                            weights = customLevel.weights.map(w => new Weight(w.x, w.y, w.mass, w.color));
                            platforms = customLevel.platforms.map(p => new MovingPlatform(p.x, p.y, p.width, p.speed, p.rangeX));
                            gameTime = customLevel.time || 60;
                            document.getElementById('menu').classList.add('hidden');
                        } catch (e) {
                            alert('Invalid level code!');
                        }
                    }
                });

                // Game loop
                function update() {
                    if (gameState === 'playing') {
                        // Update timer
                        const now = Date.now();
                        if (now - lastSecond >= 1000) {
                            gameTime--;
                            lastSecond = now;
                            if (gameTime <= 0) {
                                alert('Time\'s up! Try again.');
                                loadLevel(currentLevel);
                            }
                        }

                        // Update platforms
                        platforms.forEach(platform => platform.update());

                        // Update weights physics
                        weights.forEach(weight => {
                            if (!weight.isDragging) {
                                weight.vy += GRAVITY;
                                weight.y += weight.vy;
                                weight.x += weight.vx;

                                // Check platform collisions
                                let onPlatform = false;
                                platforms.forEach(platform => {
                                    if (platform.isOn(weight) && weight.vy >= 0) {
                                        weight.y = platform.y;
                                        weight.vy = 0;
                                        weight.vx = platform.speed * platform.direction;
                                        onPlatform = true;
                                    }
                                });

                                // Check scale collision
                                if (scale.isOnPlatform(weight)) {
                                    weight.y = scale.y + Math.sin(scale.angle) * (weight.x - scale.x);
                                    weight.vy = 0;
                                    weight.vx *= 0.95;
                                    onPlatform = true;
                                }

                                // Floor collision
                                if (weight.y > canvas.height - weight.size / 2) {
                                    weight.y = canvas.height - weight.size / 2;
                                    weight.vy = 0;
                                    weight.vx *= 0.8;
                                }

                                // Wall collision
                                if (weight.x < weight.size / 2) {
                                    weight.x = weight.size / 2;
                                    weight.vx = 0;
                                }
                                if (weight.x > canvas.width - weight.size / 2) {
                                    weight.x = canvas.width - weight.size / 2;
                                    weight.vx = 0;
                                }
                            }
                        });

                        // Calculate balance
                        const torques = scale.calculateTorque(weights);
                        const totalTorque = torques.leftTorque + torques.rightTorque;
                        if (totalTorque > 0) {
                            const balance = 100 - (Math.abs(torques.netTorque) / totalTorque * 100);
                            balancePercentage = Math.max(0, balance);
                        } else {
                            balancePercentage = 0;
                        }

                        // Check win condition
                        if (balancePercentage >= 90) {
                            setTimeout(() => {
                                alert(`Level ${currentLevel + 1} Complete!
Balance: ${balancePercentage.toFixed(1)}%`);
                                currentLevel++;
                                if (currentLevel < levels.length) {
                                    loadLevel(currentLevel);
                                } else {
                                    alert('Congratulations! You completed all levels!');
                                    gameState = 'menu';
                                    document.getElementById('menu').classList.remove('hidden');
                                }
                            }, 100);
                        }

                        // Update UI
                        document.getElementById('timeInfo').textContent = `Time: ${gameTime}s`;
                        document.getElementById('balanceInfo').textContent = `Balance: ${balancePercentage.toFixed(1)}%`;
                    }
                }

                function draw() {
                    // Clear canvas
                    ctx.fillStyle = '#1a1a2e';
                    ctx.fillRect(0, 0, canvas.width, canvas.height);

                    if (gameState === 'menu') {
                        // Menu is handled by HTML
                        return;
                    }

                    if (gameState === 'editor') {
                        // Draw editor
                        ctx.fillStyle = '#fff';
                        ctx.font = '20px Arial';
                        ctx.fillText('Level Editor - Click to place objects', 10, 30);
                        ctx.fillText('Press 1: Weight, 2: Scale, 3: Platform', 10, 60);
                        ctx.fillText('Press S to save level code', 10, 90);

                        editorObjects.forEach(obj => {
                            if (obj.type === 'weight') {
                                ctx.fillStyle = obj.color;
                                ctx.beginPath();
                                ctx.arc(obj.x, obj.y, 25, 0, Math.PI * 2);
                                ctx.fill();
                                ctx.strokeStyle = '#fff';
                                ctx.lineWidth = 2;
                                ctx.stroke();
                            } else if (obj.type === 'scale') {
                                ctx.fillStyle = '#CD853F';
                                ctx.fillRect(obj.x - obj.width / 2, obj.y - 10, obj.width, 20);
                            } else if (obj.type === 'platform') {
                                ctx.fillStyle = '#4CAF50';
                                ctx.fillRect(obj.x - obj.width / 2, obj.y, obj.width, 15);
                            }
                        });

                        // Handle editor keys
                        if (keys['1']) editorSelectedType = 'weight';
                        if (keys['2']) editorSelectedType = 'scale';
                        if (keys['3']) editorSelectedType = 'platform';
                        if (keys['s'] || keys['S']) {
                            const levelData = {
                                scale: editorObjects.find(o => o.type === 'scale') || { x: 400, y: 300, width: 300 },
                                weights: editorObjects.filter(o => o.type === 'weight'),
                                platforms: editorObjects.filter(o => o.type === 'platform'),
                                time: 60
                            };
                            const code = btoa(JSON.stringify(levelData));
                            prompt('Level code (copy and share):', code);
                            keys['s'] = false;
                            keys['S'] = false;
                        }
                        return;
                    }

                    // Draw game
                    if (scale) scale.draw();
                    platforms.forEach(platform => platform.draw());
                    weights.forEach(weight => weight.draw());

                    // Draw balance indicator
                    const barWidth = 200;
                    const barHeight = 20;
                    const barX = canvas.width - barWidth - 20;
                    const barY = 20;
                    
                    ctx.fillStyle = '#333';
                    ctx.fillRect(barX, barY, barWidth, barHeight);
                    
                    const fillWidth = (balancePercentage / 100) * barWidth;
                    const color = balancePercentage >= 90 ? '#4CAF50' : balancePercentage >= 50 ? '#FFA500' : '#FF6347';
                    ctx.fillStyle = color;
                    ctx.fillRect(barX, barY, fillWidth, barHeight);
                    
                    ctx.strokeStyle = '#fff';
                    ctx.lineWidth = 2;
                    ctx.strokeRect(barX, barY, barWidth, barHeight);
                }

                function gameLoop() {
                    update();
                    draw();
                    requestAnimationFrame(gameLoop);
                }

                gameLoop();

            } catch(e) {
                document.body.innerHTML = '<div style="color:white;padding:20px;font-size:20px;">Game error: ' + e.message + '<br><br>Stack: ' + e.stack + '</div>';
            }
        });
    </script>
</body>
</html>

Improving Your Game...

Analyzing your request...

This usually takes 1-3 minutes

📱

Install GB3A

Install GB3A on your device for a better experience!