Ice Castle Level Editor

HTML

<div class="title">ЭЛЬЗАТЬКА</div>
    
    <div class="controls">
        <div class="control-group">
            <label>Background:</label>
            <input type="url" id="bgUrlInput" placeholder="https://i.imgur.com/MtltzX8.png" value="https://i.imgur.com/MtltzX8.png" onchange="loadBackgroundFromUrl()">
            <input type="file" id="bgImageInput" accept="image/*" onchange="loadBackgroundImage(event)">
        </div>
        
        <div class="control-group">
            <label>Player Sprite:</label>
            <input type="url" id="playerUrlInput" placeholder="https://i.imgur.com/NPRfgJ4.png" value="https://i.imgur.com/NPRfgJ4.png" onchange="loadPlayerFromUrl()">
            <input type="file" id="playerImageInput" accept="image/*" onchange="loadPlayerImage(event)">
        </div>
        
        <button id="modeBtn" onclick="toggleMode()">Mode: GAME</button>
        <button onclick="clearPlatforms()">Clear All</button>
        <button onclick="addPlatform()">Add Platform</button>
        
        <div class="opacity-control">
            <label>Colliders:</label>
            <input type="range" id="opacitySlider" min="0" max="100" value="70" onchange="updateOpacity()">
            <span id="opacityValue">70%</span>
        </div>
        
        <span id="info">GAME MODE: Use ARROW KEYS or WASD to move and jump</span>
    </div>
    
    <canvas id="gameCanvas" width="1408" height="768"></canvas>
    
    <textarea id="exportArea" placeholder="Exported level data will appear here..."></textarea>

CSS

body { margin: 0; padding: 0; background: #1a1a2e; display: flex; flex-direction: column; align-items: center; min-height: 100vh; font-family: monospace; color: white; }
        .title { font-size: 32px; font-weight: bold; color: #87ceeb; margin: 20px 0; text-shadow: 0 0 10px rgba(135, 206, 235, 0.5); animation: pulse 2s ease-in-out infinite; }
        @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
        canvas { border: 2px solid #87ceeb; background: #2a4d7a; image-rendering: pixelated; cursor: crosshair; }
        .controls { margin: 10px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
        .control-group { display: flex; flex-direction: column; gap: 5px; border: 1px solid #4682b4; padding: 10px; border-radius: 4px; }
        .control-group label { font-size: 12px; color: #87ceeb; }
        button { background: #4682b4; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-family: monospace; }
        button:hover { background: #5a9bd4; }
        button.active { background: #87ceeb; color: #000; }
        input[type="file"], input[type="url"] { background: #4682b4; color: white; border: none; padding: 8px 16px; border-radius: 4px; font-family: monospace; width: 200px; }
        textarea { width: 800px; height: 100px; font-family: monospace; font-size: 12px; background: #1a1a2e; color: white; border: 1px solid #4682b4; padding: 10px; margin: 10px; }
        .opacity-control { display: flex; align-items: center; gap: 10px; }
        input[type="range"] { width: 100px; }

JavaScript

const DEFAULT_BG = 'https://i.imgur.com/MtltzX8.png';
        const DEFAULT_PLAYER = 'https://i.imgur.com/NPRfgJ4.png';
        
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        
        let editMode = false, selectedPlatform = null, selectedPlayer = false, dragOffset = {x:0,y:0};
        let isDragging = false, isResizing = false, backgroundImage = null, playerImage = null;
        let colliderOpacity = 0.7, playerResizeHandle = false;

        const PHYSICS = { gravity: 0.25, jumpPower: -9.75, moveAccel: 0.2, maxSpeed: 2.0, friction: 0.88, terminalVelocity: 7 };

        const game = {
            player: { x: 64, y: 600, width: 32, height: 40, vx: 0, vy: 0, grounded: false, color: '#87ceeb' },
            playerSpawn: {x: 64, y: 600},
            platforms: [
                {x: 324, y: 395, width: 262, height: 53}, {x: 660, y: 340, width: 127, height: 53},
                {x: 1192, y: 670, width: 216, height: 61}, {x: 479, y: 155, width: 127, height: 49},
                {x: 840, y: 0, width: 568, height: 38}, {x: 825, y: 276, width: 127, height: 51},
                {x: 1083, y: 326, width: 238, height: 55}, {x: 816, y: 511, width: 128, height: 52},
                {x: 0, y: 663, width: 651, height: 102}, {x: 684, y: 572, width: 131, height: 52},
                {x: 0, y: 238, width: 56, height: 69}, {x: 603, y: 575, width: 57, height: 188},
                {x: 1095, y: 732, width: 313, height: 36}, {x: 136, y: 60, width: 80, height: 20},
                {x: 1299, y: 581, width: 109, height: 92}
            ],
            canvas: {width: 1408, height: 768},
            castle: {x: 1200, y: 100, width: 60, height: 100},
            snowflakes: [],
            keys: {}
        };

        for (let i = 0; i < 30; i++) {
            game.snowflakes.push({
                x: Math.random() * canvas.width, y: Math.random() * canvas.height,
                size:...