nethanlose adlı üyeden alıntı: mesajı görüntüle
Birazda ben geliştirdim elinize sağlık
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Dart Arrow</title>
    <style>
        * {
            box-sizing: border-box;
            user-select: none;
            -webkit-user-select: none;
            -webkit-tap-highlight-color: transparent;
        }

        :root {
            --bg: #eef0f3;
            --panel: rgba(255, 255, 255, 0.88);
            --ink: #111318;
            --muted: #69707d;
            --line: rgba(17, 19, 24, 0.12);
            --accent: #0f8f72;
            --danger: #d94444;
            --gold: #d99b19;
            --shadow: 0 20px 55px rgba(24, 29, 38, 0.18);
        }

        body.dark {
            --bg: #171a21;
            --panel: rgba(31, 35, 44, 0.92);
            --ink: #f5f6f8;
            --muted: #aeb5c2;
            --line: rgba(245, 246, 248, 0.14);
            --accent: #26c6a2;
            --danger: #ff6b6b;
            --gold: #ffc247;
            --shadow: 0 20px 55px rgba(0, 0, 0, 0.35);
        }

        html,
        body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            font-family: Arial, Helvetica, sans-serif;
            background: radial-gradient(circle at 50% 10%, #ffffff 0, var(--bg) 58%);
            color: var(--ink);
            touch-action: none;
        }

        body.dark {
            background: radial-gradient(circle at 50% 10%, #2b303b 0, var(--bg) 58%);
        }

        #gameContainer {
            position: relative;
            width: 100%;
            max-width: 460px;
            height: 100%;
            max-height: 820px;
            margin: 0 auto;
            overflow: hidden;
            background: var(--bg);
            box-shadow: var(--shadow);
        }

        canvas {
            display: block;
            width: 100%;
            height: 100%;
        }

        #topBar {
            position: absolute;
            top: 14px;
            left: 14px;
            right: 14px;
            z-index: 4;
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            gap: 10px;
            pointer-events: none;
        }

        .stats {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            min-width: 0;
        }

        .pill {
            min-width: 62px;
            padding: 7px 10px;
            border: 1px solid var(--line);
            border-radius: 8px;
            background: var(--panel);
            color: var(--ink);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
            backdrop-filter: blur(10px);
            font-size: 11px;
            font-weight: 700;
            line-height: 1.15;
            letter-spacing: 0;
        }

        .pill span {
            display: block;
            margin-top: 3px;
            font-size: 18px;
        }

        .iconRow {
            display: flex;
            gap: 8px;
            pointer-events: auto;
        }

        .iconBtn {
            width: 40px;
            height: 40px;
            display: grid;
            place-items: center;
            border: 1px solid var(--line);
            border-radius: 8px;
            background: var(--panel);
            color: var(--ink);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
            cursor: pointer;
            font-size: 18px;
        }

        .overlay {
            position: absolute;
            inset: 0;
            z-index: 8;
            display: none;
            align-items: center;
            justify-content: center;
            padding: 22px;
            background: rgba(238, 240, 243, 0.72);
            backdrop-filter: blur(12px);
        }

        body.dark .overlay {
            background: rgba(23, 26, 33, 0.72);
        }

        .overlay.show {
            display: flex;
        }

        .panel {
            width: min(100%, 390px);
            padding: 22px;
            border: 1px solid var(--line);
            border-radius: 8px;
            background: var(--panel);
            box-shadow: var(--shadow);
        }

        .title {
            margin: 0 0 6px;
            font-size: 40px;
            line-height: 1;
            letter-spacing: 0;
        }

        .subtitle {
            margin: 0 0 18px;
            color: var(--muted);
            font-size: 14px;
            line-height: 1.35;
        }

        .menuGrid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin: 12px 0;
        }

        .wide {
            grid-column: 1 / -1;
        }

        .btn {
            width: 100%;
            min-height: 48px;
            padding: 12px 14px;
            border: 1px solid transparent;
            border-radius: 8px;
            background: var(--ink);
            color: var(--bg);
            cursor: pointer;
            font-size: 15px;
            font-weight: 700;
        }

        .btn.secondary {
            border-color: var(--line);
            background: transparent;
            color: var(--ink);
        }

        .btn.accent {
            background: var(--accent);
            color: #ffffff;
        }

        .btn:active,
        .iconBtn:active {
            transform: scale(0.97);
        }

        .setting {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            padding: 12px 0;
            border-top: 1px solid var(--line);
            font-size: 14px;
            font-weight: 700;
        }

        .setting small {
            display: block;
            margin-top: 3px;
            color: var(--muted);
            font-size: 12px;
            font-weight: 400;
        }

        .switch {
            position: relative;
            width: 48px;
            height: 28px;
            flex: 0 0 auto;
        }

        .switch input {
            display: none;
        }

        .slider {
            position: absolute;
            inset: 0;
            border-radius: 999px;
            background: #adb3bd;
            cursor: pointer;
        }

        .slider::after {
            content: "";
            position: absolute;
            width: 22px;
            height: 22px;
            top: 3px;
            left: 3px;
            border-radius: 50%;
            background: #ffffff;
            transition: transform 0.18s;
        }

        .switch input:checked + .slider {
            background: var(--accent);
        }

        .switch input:checked + .slider::after {
            transform: translateX(20px);
        }

        #messageTitle {
            margin: 0 0 8px;
            font-size: 36px;
            line-height: 1.05;
        }

        #messageDetail {
            margin: 0 0 18px;
            color: var(--muted);
            line-height: 1.35;
        }

        #countdown {
            position: absolute;
            inset: 0;
            z-index: 7;
            display: none;
            align-items: center;
            justify-content: center;
            font-size: 96px;
            font-weight: 900;
            color: var(--ink);
            text-shadow: 0 8px 30px rgba(0, 0, 0, 0.16);
            pointer-events: none;
        }

        #countdown.show {
            display: flex;
            animation: pop 0.35s ease;
        }

        @keyframes pop {
            from { transform: scale(0.7); opacity: 0; }
            to { transform: scale(1); opacity: 1; }
        }

        @media (max-width: 360px) {
            .title { font-size: 34px; }
            .pill { min-width: 56px; padding: 6px 8px; }
            .pill span { font-size: 16px; }
            .iconBtn { width: 36px; height: 36px; }
        }
    </style>
</head>
<body>
<div id="gameContainer">
    <canvas id="gameCanvas"></canvas>

    <div id="topBar">
        <div class="stats">
            <div class="pill">SEVİYE<span id="levelDisplay">1</span></div>
            <div class="pill">REKOR<span id="bestDisplay">1</span></div>
            <div class="pill">MOD<span id="modeDisplay">Klasik</span></div>
        </div>
        <div class="iconRow">
            <button class="iconBtn" id="pauseBtn" title="Duraklat">⏸</button>
            <button class="iconBtn" id="restartBtn" title="Yeniden başlat">↻</button>
        </div>
    </div>

    <div id="countdown">3</div>

    <div class="overlay show" id="menuOverlay">
        <div class="panel">
            <h1 class="title">Dart Arrow</h1>
            <p class="subtitle">Doğru anda ateş et, çarpışmadan tüm iğneleri hedefe yerleştir.</p>
            <div class="menuGrid">
                <button class="btn accent wide" id="continueBtn">Devam Et</button>
                <button class="btn" data-mode="classic">Klasik</button>
                <button class="btn secondary" data-mode="endless">Sonsuz</button>
                <button class="btn secondary" data-mode="timed">Zamanlı</button>
                <button class="btn secondary" data-mode="hard">Zor</button>
            </div>
            <div class="setting">
                <div>Ses<small>Atış, başarı ve çarpışma sesleri</small></div>
                <label class="switch">
                    <input type="checkbox" id="soundToggle" checked>
                    <span class="slider"></span>
                </label>
            </div>
            <div class="setting">
                <div>Titreşim<small>Destekleyen telefonlarda dokunsal geri bildirim</small></div>
                <label class="switch">
                    <input type="checkbox" id="vibrationToggle" checked>
                    <span class="slider"></span>
                </label>
            </div>
            <div class="setting">
                <div>Karanlık Tema<small>Düşük ışıkta daha rahat oyun</small></div>
                <label class="switch">
                    <input type="checkbox" id="themeToggle">
                    <span class="slider"></span>
                </label>
            </div>
        </div>
    </div>

    <div class="overlay" id="messageOverlay">
        <div class="panel">
            <h2 id="messageTitle">Yandın!</h2>
            <p id="messageDetail">Aynı noktaya denk geldi.</p>
            <div class="menuGrid">
                <button class="btn accent wide" id="primaryActionBtn">Tekrar Dene</button>
                <button class="btn secondary" id="menuBtn">Menü</button>
                <button class="btn secondary" id="nextActionBtn">Sonraki Seviye</button>
            </div>
        </div>
    </div>
</div>

<script>
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    const levelDisplay = document.getElementById('levelDisplay');
    const bestDisplay = document.getElementById('bestDisplay');
    const modeDisplay = document.getElementById('modeDisplay');
    const menuOverlay = document.getElementById('menuOverlay');
    const messageOverlay = document.getElementById('messageOverlay');
    const messageTitle = document.getElementById('messageTitle');
    const messageDetail = document.getElementById('messageDetail');
    const primaryActionBtn = document.getElementById('primaryActionBtn');
    const nextActionBtn = document.getElementById('nextActionBtn');
    const menuBtn = document.getElementById('menuBtn');
    const pauseBtn = document.getElementById('pauseBtn');
    const restartBtn = document.getElementById('restartBtn');
    const continueBtn = document.getElementById('continueBtn');
    const countdownEl = document.getElementById('countdown');
    const soundToggle = document.getElementById('soundToggle');
    const vibrationToggle = document.getElementById('vibrationToggle');
    const themeToggle = document.getElementById('themeToggle');

    const TAU = Math.PI * 2;
    const maxLevel = 1200;
    const storageKey = 'dartArrowSaveV2';
    const modes = {
        classic: 'Klasik',
        endless: 'Sonsuz',
        timed: 'Zamanlı',
        hard: 'Zor'
    };

    let state = loadState();
    let gameState = 'MENU';
    let targetAngle = 0;
    let targetSpeed = 0.02;
    let targetRadius = 50;
    let pinRadius = 12;
    let pinLineLength = 138;
    let bulletSpeed = 25;
    let startingBulletsCount = 0;
    let timer = 0;
    let levelStartedAt = 0;
    let pausedRemainingTime = 0;
    let lastTime = performance.now();
    let pins = [];
    let bullets = [];
    let activeBullet = null;
    let particles = [];
    let flash = null;
    let audioCtx = null;
    let countdownToken = 0;

    function loadState() {
        const fallback = {
            level: 1,
            best: 1,
            mode: 'classic',
            sound: true,
            vibration: true,
            dark: false
        };

        try {
            return { ...fallback, ...JSON.parse(localStorage.getItem(storageKey) || '{}') };
        } catch (error) {
            return fallback;
        }
    }

    function saveState() {
        localStorage.setItem(storageKey, JSON.stringify(state));
    }

    function resizeCanvas() {
        const dpr = Math.max(1, Math.min(window.devicePixelRatio || 1, 2));
        const rect = canvas.parentElement.getBoundingClientRect();
        canvas.width = Math.floor(rect.width * dpr);
        canvas.height = Math.floor(rect.height * dpr);
        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
        canvas.logicalWidth = rect.width;
        canvas.logicalHeight = rect.height;
        pinLineLength = Math.max(105, Math.min(145, rect.height * 0.18));
        targetRadius = Math.max(42, Math.min(54, rect.width * 0.115));
    }

    function updateHud() {
        levelDisplay.textContent = state.level;
        bestDisplay.textContent = state.best;
        modeDisplay.textContent = modes[state.mode];
        soundToggle.checked = state.sound;
        vibrationToggle.checked = state.vibration;
        themeToggle.checked = state.dark;
        document.body.classList.toggle('dark', state.dark);
        continueBtn.textContent = state.best > 1 ? 'Devam Et - Seviye ' + state.level : 'Başla';
        saveState();
    }

    function getDifficulty() {
        const level = state.mode === 'endless' ? Math.min(state.level, 2000) : state.level;
        const curve = Math.log2(level + 1);
        const hardBoost = state.mode === 'hard' ? 1.35 : 1;
        const timedBoost = state.mode === 'timed' ? 1.12 : 1;
        const speedBase = 0.010 + curve * 0.0042;
        const speedWave = Math.sin(level * 0.73) * 0.006;
        const speed = Math.min(0.09, (speedBase + speedWave) * hardBoost * timedBoost);
        const initialPins = Math.min(state.mode === 'hard' ? 13 : 11, 2 + Math.floor(level / 5) + Math.floor(curve / 2));
        const bulletsCount = Math.min(state.mode === 'hard' ? 30 : 26, 5 + Math.floor(level / 3) + (level % 4 === 0 ? 2 : 0));
        const direction = level % 3 === 0 ? -1 : 1;
        const wobble = level >= 8 || state.mode !== 'classic';
        const stopGo = level >= 14 || state.mode === 'hard';
        const timeLimit = state.mode === 'timed' ? Math.max(7, 16 - Math.floor(level / 12)) : 0;

        return {
            speed: speed * direction,
            initialPins,
            bulletsCount,
            wobble,
            stopGo,
            timeLimit
        };
    }

    function initLevel(skipCountdown = false) {
        resizeCanvas();
        const difficulty = getDifficulty();
        targetAngle = 0;
        targetSpeed = difficulty.speed;
        startingBulletsCount = difficulty.bulletsCount;
        timer = difficulty.timeLimit;
        pausedRemainingTime = timer;
        levelStartedAt = performance.now();
        pins = [];
        bullets = [];
        activeBullet = null;
        particles = [];
        flash = null;

        const jitter = state.mode === 'classic' && state.level < 5 ? 0 : 0.18;
        for (let i = 0; i < difficulty.initialPins; i++) {
            const offset = Math.sin((state.level + i) * 1.77) * jitter;
            pins.push({
                angle: normalize((TAU / difficulty.initialPins) * i + offset),
                num: ''
            });
        }

        for (let i = startingBulletsCount; i > 0; i--) {
            bullets.push(i);
        }

        gameState = skipCountdown ? 'PLAYING' : 'COUNTDOWN';
        menuOverlay.classList.remove('show');
        messageOverlay.classList.remove('show');
        updateHud();

        if (skipCountdown) {
            return;
        }

        runCountdown();
    }

    function runCountdown() {
        const token = ++countdownToken;
        let count = 3;
        countdownEl.textContent = count;
        countdownEl.classList.add('show');
        tone(520, 0.06, 'sine', 0.04);

        const tick = () => {
            if (token !== countdownToken || gameState !== 'COUNTDOWN') return;
            count--;
            if (count > 0) {
                countdownEl.textContent = count;
                countdownEl.classList.remove('show');
                void countdownEl.offsetWidth;
                countdownEl.classList.add('show');
                tone(520 + count * 50, 0.06, 'sine', 0.04);
                setTimeout(tick, 650);
            } else {
                countdownEl.textContent = 'GO';
                countdownEl.classList.remove('show');
                void countdownEl.offsetWidth;
                countdownEl.classList.add('show');
                tone(760, 0.1, 'triangle', 0.05);
                setTimeout(() => {
                    if (token === countdownToken) {
                        countdownEl.classList.remove('show');
                        gameState = 'PLAYING';
                        levelStartedAt = performance.now();
                    }
                }, 450);
            }
        };

        setTimeout(tick, 650);
    }

    function normalize(angle) {
        return (angle % TAU + TAU) % TAU;
    }

    function draw() {
        const width = canvas.logicalWidth || canvas.width;
        const height = canvas.logicalHeight || canvas.height;
        const cx = width / 2;
        const cy = height * 0.36;
        const remaining = bullets.length + (activeBullet ? 1 : 0);

        ctx.clearRect(0, 0, width, height);
        drawBackground(width, height);
        drawTarget(cx, cy, remaining);
        drawActiveBullet(cx);
        drawQueue(cx, height);
        drawParticles();
        drawPrompts(cx, height);

        if (flash) {
            ctx.fillStyle = flash.color;
            ctx.globalAlpha = Math.max(0, flash.life);
            ctx.fillRect(0, 0, width, height);
            ctx.globalAlpha = 1;
        }
    }

    function drawBackground(width, height) {
        const gradient = ctx.createLinearGradient(0, 0, 0, height);
        if (document.body.classList.contains('dark')) {
            gradient.addColorStop(0, '#252a33');
            gradient.addColorStop(1, '#171a21');
        } else {
            gradient.addColorStop(0, '#fbfbfc');
            gradient.addColorStop(1, '#e8ebef');
        }
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, width, height);

        ctx.strokeStyle = document.body.classList.contains('dark') ? 'rgba(255,255,255,0.035)' : 'rgba(0,0,0,0.035)';
        ctx.lineWidth = 1;
        for (let y = 95; y < height; y += 44) {
            ctx.beginPath();
            ctx.moveTo(0, y);
            ctx.lineTo(width, y);
            ctx.stroke();
        }
    }

    function drawTarget(cx, cy, remaining) {
        const ink = getInk();
        ctx.save();
        ctx.translate(cx, cy);
        ctx.rotate(targetAngle);

        pins.forEach(pin => {
            const px = Math.cos(pin.angle) * pinLineLength;
            const py = Math.sin(pin.angle) * pinLineLength;
            ctx.beginPath();
            ctx.moveTo(0, 0);
            ctx.lineTo(px, py);
            ctx.strokeStyle = ink;
            ctx.lineWidth = 2;
            ctx.stroke();

            ctx.beginPath();
            ctx.arc(px, py, pinRadius, 0, TAU);
            ctx.fillStyle = ink;
            ctx.fill();

            if (pin.num !== '') {
                ctx.save();
                ctx.translate(px, py);
                ctx.rotate(-targetAngle);
                drawSmallNumber(pin.num, 0, 1);
                ctx.restore();
            }
        });

        ctx.beginPath();
        ctx.arc(0, 0, targetRadius + 4, 0, TAU);
        ctx.fillStyle = state.mode === 'hard' ? '#d94444' : state.mode === 'timed' ? '#d99b19' : ink;
        ctx.fill();

        ctx.beginPath();
        ctx.arc(0, 0, targetRadius - 7, 0, TAU);
        ctx.fillStyle = ink;
        ctx.fill();

        ctx.rotate(-targetAngle);
        ctx.fillStyle = '#ffffff';
        ctx.font = '900 ' + (remaining >= 100 ? 32 : 44) + 'px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(remaining, 0, 2);
        ctx.restore();
    }

    function drawActiveBullet(cx) {
        if (!activeBullet) return;
        const ink = getInk();
        ctx.beginPath();
        ctx.moveTo(cx, activeBullet.y);
        ctx.lineTo(cx, activeBullet.y + 22);
        ctx.strokeStyle = ink;
        ctx.lineWidth = 2;
        ctx.stroke();

        ctx.beginPath();
        ctx.arc(cx, activeBullet.y, pinRadius, 0, TAU);
        ctx.fillStyle = ink;
        ctx.fill();
        drawSmallNumber(activeBullet.num, cx, activeBullet.y + 1);
    }

    function drawQueue(cx, height) {
        const ink = getInk();
        const bulletStartY = height * 0.74;
        const spacing = pinRadius * 2.35;
        const showCount = Math.min(7, bullets.length);

        for (let i = 0; i < showCount; i++) {
            const by = bulletStartY + (i * spacing);
            ctx.beginPath();
            ctx.arc(cx, by, pinRadius, 0, TAU);
            ctx.fillStyle = ink;
            ctx.fill();
            drawSmallNumber(bullets[bullets.length - 1 - i], cx, by + 1);
        }

        if (bullets.length > showCount) {
            ctx.fillStyle = getMuted();
            ctx.font = 'bold 13px Arial';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText('+' + (bullets.length - showCount), cx, bulletStartY + showCount * spacing + 4);
        }
    }

    function drawSmallNumber(text, x, y) {
        ctx.fillStyle = '#ffffff';
        ctx.font = 'bold 12px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(text, x, y);
    }

    function drawPrompts(cx, height) {
        if (gameState === 'PLAYING' && bullets.length === startingBulletsCount && !activeBullet) {
            ctx.fillStyle = getMuted();
            ctx.font = 'bold 20px Arial';
            ctx.textAlign = 'center';
            ctx.fillText('Ateş etmek için dokun', cx, height * 0.62);
        }

        if (gameState === 'PAUSED') {
            ctx.fillStyle = 'rgba(0,0,0,0.35)';
            ctx.fillRect(0, 0, canvas.logicalWidth, canvas.logicalHeight);
            ctx.fillStyle = '#ffffff';
            ctx.font = '900 42px Arial';
            ctx.textAlign = 'center';
            ctx.fillText('DURAKLATILDI', canvas.logicalWidth / 2, canvas.logicalHeight / 2);
        }

        if (state.mode === 'timed' && gameState === 'PLAYING') {
            const timeLeft = Math.max(0, timer - (performance.now() - levelStartedAt) / 1000);
            ctx.fillStyle = timeLeft <= 3 ? '#d94444' : getInk();
            ctx.font = '900 18px Arial';
            ctx.textAlign = 'right';
            ctx.fillText(timeLeft.toFixed(1), canvas.logicalWidth - 18, 96);
        }
    }

    function drawParticles() {
        particles.forEach(p => {
            ctx.globalAlpha = Math.max(0, p.life);
            ctx.beginPath();
            ctx.arc(p.x, p.y, p.size, 0, TAU);
            ctx.fillStyle = p.color;
            ctx.fill();
        });
        ctx.globalAlpha = 1;
    }

    function update(now) {
        const dt = Math.min(32, now - lastTime);
        lastTime = now;

        updateParticles(dt);
        if (flash) {
            flash.life -= dt / 220;
            if (flash.life <= 0) flash = null;
        }

        if (gameState !== 'PLAYING') return;

        const difficulty = getDifficulty();
        const elapsed = (now - levelStartedAt) / 1000;
        let speedMultiplier = 1;
        if (difficulty.wobble) speedMultiplier += Math.sin(elapsed * 2.4) * 0.28;
        if (difficulty.stopGo && Math.sin(elapsed * 1.35) > 0.72) speedMultiplier = 0.18;
        targetAngle += targetSpeed * speedMultiplier * (dt / 16.67);

        if (state.mode === 'timed' && elapsed >= timer) {
            fail('Süre Bitti!', 'Bu seviyede daha hızlı ateş etmelisin.');
            return;
        }

        if (!activeBullet) return;

        activeBullet.y -= bulletSpeed * (dt / 16.67);
        const cy = canvas.logicalHeight * 0.36;

        if (activeBullet.y <= cy + pinLineLength) {
            let hitAngle = normalize((Math.PI / 2) - targetAngle);
            let collision = false;

            for (let i = 0; i < pins.length; i++) {
                let pinAngle = normalize(pins[i].angle);
                let diff = Math.abs(hitAngle - pinAngle);
                if (diff > Math.PI) diff = TAU - diff;

                const distance = 2 * pinLineLength * Math.sin(diff / 2);
                if (distance < pinRadius * 2 + 2) {
                    collision = true;
                    break;
                }
            }

            if (collision) {
                fail('Yandın!', 'İğne başka bir iğneye çarptı.');
            } else {
                pins.push({ angle: hitAngle, num: activeBullet.num });
                burst(canvas.logicalWidth / 2, cy + pinLineLength, getAccent(), 8);
                activeBullet = null;
                tone(420, 0.045, 'triangle', 0.035);

                if (bullets.length === 0) {
                    success();
                }
            }
        }
    }

    function updateParticles(dt) {
        particles = particles.filter(p => {
            p.x += p.vx * dt;
            p.y += p.vy * dt;
            p.vy += 0.0009 * dt;
            p.life -= dt / p.decay;
            return p.life > 0;
        });
    }

    function shoot(event) {
        if (event) event.preventDefault();
        if (gameState === 'COUNTDOWN') return;
        if (gameState === 'PAUSED') {
            resumeGame();
            return;
        }
        if (gameState !== 'PLAYING' || activeBullet || bullets.length === 0) return;

        const num = bullets.pop();
        activeBullet = {
            y: canvas.logicalHeight * 0.74,
            num
        };
        tone(260, 0.055, 'square', 0.025);
        vibrate(12);
    }

    function fail(title, detail) {
        gameState = 'GAMEOVER';
        activeBullet = null;
        flash = { color: 'rgba(217, 68, 68, 0.42)', life: 1 };
        burst(canvas.logicalWidth / 2, canvas.logicalHeight * 0.36, '#d94444', 24);
        tone(120, 0.22, 'sawtooth', 0.05);
        vibrate([50, 30, 80]);
        showMessage(title, detail, false);
    }

    function success() {
        gameState = 'SUCCESS';
        flash = { color: 'rgba(15, 143, 114, 0.32)', life: 1 };
        burst(canvas.logicalWidth / 2, canvas.logicalHeight * 0.36, getAccent(), 34);
        tone(620, 0.08, 'triangle', 0.04);
        setTimeout(() => tone(820, 0.11, 'triangle', 0.035), 85);
        vibrate(35);

        if (state.mode === 'classic' || state.mode === 'timed' || state.mode === 'hard') {
            state.level = Math.min(maxLevel, state.level + 1);
        } else {
            state.level++;
        }

        state.best = Math.max(state.best, state.level);
        updateHud();
        showMessage('Harika!', 'Seviye tamamlandı. Yeni seviye hazır.', true);
    }

    function showMessage(title, detail, won) {
        messageTitle.textContent = title;
        messageDetail.textContent = detail;
        primaryActionBtn.textContent = won ? 'Devam Et' : 'Tekrar Dene';
        nextActionBtn.style.display = won ? 'block' : 'none';
        setTimeout(() => messageOverlay.classList.add('show'), 260);
    }

    function burst(x, y, color, count) {
        for (let i = 0; i < count; i++) {
            const angle = (TAU / count) * i + Math.random() * 0.3;
            const speed = 0.08 + Math.random() * 0.18;
            particles.push({
                x,
                y,
                vx: Math.cos(angle) * speed,
                vy: Math.sin(angle) * speed,
                size: 2 + Math.random() * 4,
                life: 1,
                decay: 380 + Math.random() * 260,
                color
            });
        }
    }

    function tone(frequency, duration, type, volume) {
        if (!state.sound) return;
        try {
            audioCtx = audioCtx || new (window.AudioContext || window.webkitAudioContext)();
            const oscillator = audioCtx.createOscillator();
            const gain = audioCtx.createGain();
            oscillator.type = type;
            oscillator.frequency.value = frequency;
            gain.gain.setValueAtTime(volume, audioCtx.currentTime);
            gain.gain.exponentialRampToValueAtTime(0.0001, audioCtx.currentTime + duration);
            oscillator.connect(gain);
            gain.connect(audioCtx.destination);
            oscillator.start();
            oscillator.stop(audioCtx.currentTime + duration);
        } catch (error) {
            state.sound = false;
        }
    }

    function vibrate(pattern) {
        if (state.vibration && navigator.vibrate) {
            navigator.vibrate(pattern);
        }
    }

    function pauseGame() {
        if (gameState === 'PLAYING') {
            pausedRemainingTime = getRemainingTime();
            gameState = 'PAUSED';
            pauseBtn.textContent = '▶';
        }
    }

    function resumeGame() {
        if (gameState === 'PAUSED') {
            gameState = 'PLAYING';
            levelStartedAt = performance.now() - Math.max(0, timer - pausedRemainingTime) * 1000;
            pauseBtn.textContent = '⏸';
        }
    }

    function getRemainingTime() {
        if (state.mode !== 'timed') return 0;
        return Math.max(0, timer - (performance.now() - levelStartedAt) / 1000);
    }

    function openMenu() {
        gameState = 'MENU';
        countdownToken++;
        countdownEl.classList.remove('show');
        messageOverlay.classList.remove('show');
        menuOverlay.classList.add('show');
        pauseBtn.textContent = '⏸';
    }

    function getInk() {
        return document.body.classList.contains('dark') ? '#f5f6f8' : '#111318';
    }

    function getMuted() {
        return document.body.classList.contains('dark') ? 'rgba(245,246,248,0.62)' : 'rgba(17,19,24,0.52)';
    }

    function getAccent() {
        return document.body.classList.contains('dark') ? '#26c6a2' : '#0f8f72';
    }

    function loop(now) {
        update(now);
        draw();
        requestAnimationFrame(loop);
    }

    window.addEventListener('resize', resizeCanvas);
    canvas.addEventListener('mousedown', shoot);
    canvas.addEventListener('touchstart', shoot, { passive: false });

    document.querySelectorAll('[data-mode]').forEach(button => {
        button.addEventListener('click', () => {
            state.mode = button.dataset.mode;
            state.level = state.mode === 'endless' ? 1 : Math.min(state.level, maxLevel);
            updateHud();
            initLevel();
        });
    });

    continueBtn.addEventListener('click', () => initLevel());
    primaryActionBtn.addEventListener('click', () => initLevel());
    nextActionBtn.addEventListener('click', () => initLevel());
    menuBtn.addEventListener('click', openMenu);
    restartBtn.addEventListener('click', () => initLevel());
    pauseBtn.addEventListener('click', () => {
        if (gameState === 'PAUSED') {
            resumeGame();
        } else {
            pauseGame();
        }
    });

    soundToggle.addEventListener('change', () => {
        state.sound = soundToggle.checked;
        updateHud();
    });

    vibrationToggle.addEventListener('change', () => {
        state.vibration = vibrationToggle.checked;
        updateHud();
    });

    themeToggle.addEventListener('change', () => {
        state.dark = themeToggle.checked;
        updateHud();
    });

    document.addEventListener('keydown', event => {
        if (event.code === 'Space') shoot(event);
        if (event.code === 'Escape') openMenu();
        if (event.code === 'KeyP') gameState === 'PAUSED' ? resumeGame() : pauseGame();
    });

    resizeCanvas();
    updateHud();
    initLevel(true);
    openMenu();
    requestAnimationFrame(loop);
</script>
</body>
</html>

geliştirin tabi onun için verdim zaten