<!doctype html>

<html lang="tr">

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">

<title>Mini Scratch 3.0 — Kompakt Sonsuz Kod Alanı Editörü</title>

<style>

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}

html,body{width:100%;height:100%;margin:0;padding:0;overflow:hidden;font-family:Arial,sans-serif;background:#e9ecef;color:#222;font-size:11px;user-select:none}

header{height:40px;background:#4c97ff;color:white;display:flex;align-items:center;gap:8px;padding:0 10px;font-weight:bold;z-index:20;position:relative;box-shadow:0 2px 4px rgba(0,0,0,0.15)}

header .brand{font-size:15px;margin-right:auto;display:flex;align-items:center;gap:5px}

header button{border:0;border-radius:5px;padding:5px 10px;cursor:pointer;font-weight:bold;font-size:11px;display:flex;align-items:center;gap:3px;transition:transform 0.1s}

header button:active{transform:scale(0.95)}

.run{background:#4cbf56;color:white}

.stop{background:#ffab19;color:white}

.clear{background:#ff6680;color:white}

.download{background:#ffbf00;color:#333}


main{display:grid;grid-template-columns:210px 1fr 270px;height:calc(100vh - 40px);width:100vw;overflow:hidden;position:relative}


/* Sol Panel: Kategoriler ve Palette */

.left-panel{display:flex;background:#ffffff;border-right:1px solid #d9d9d9;z-index:10;height:100%}

.categories-bar{width:52px;background:#f9f9f9;border-right:1px solid #e0e0e0;display:flex;flex-direction:column;align-items:center;padding:6px 0;gap:8px}

.cat-btn{background:none;border:none;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:3px;font-size:9px;font-weight:bold;color:#575e75;width:100%}

.cat-dot{width:16px;height:16px;border-radius:50%}

.cat-btn.active{color:#4c97ff}

.cat-btn.motion .cat-dot{background:#4c97ff}

.cat-btn.looks .cat-dot{background:#9966ff}

.cat-btn.events .cat-dot{background:#ffd500}

.cat-btn.control .cat-dot{background:#ffab19}

.cat-btn.sound .cat-dot{background:#cf63b8}


.palette-area{flex:1;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:8px;background:#ffffff}


/* Genel Blok Stilleri (Kompakt Puzzle Yapısı) */

.block{

  color:white;font-weight:bold;font-size:11px;padding:6px 10px;cursor:grab;user-select:none;

  display:inline-flex;align-items:center;gap:5px;width:fit-content;min-height:30px;

  position:relative;box-shadow:0 1px 3px rgba(0,0,0,0.15);

  clip-path: polygon(0 0, 10px 0, 14px 3px, 24px 3px, 28px 0, 100% 0, 100% calc(100% - 3px), calc(100% - 3px) 100%, 28px 100%, 24px calc(100% + 3px), 14px calc(100% + 3px), 10px 100%, 0 100%);

  margin-bottom:2px;

}

.block-hat{

  border-top-left-radius:12px;border-top-right-radius:12px;

  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 3px), calc(100% - 3px) 100%, 28px 100%, 24px calc(100% + 3px), 14px calc(100% + 3px), 10px 100%, 0 100%);

}

.b-motion{background:#4c97ff}

.b-looks{background:#9966ff}

.b-events{background:#ffd500;color:#575e75}

.b-control{background:#ffab19}

.b-sound{background:#cf63b8}

.block input{width:38px;border:none;border-radius:8px;padding:2px 4px;text-align:center;font-weight:bold;font-size:10px;outline:none;background:white;color:#333}


/* Orta Panel: Sonsuz Açık Gri Kod Alanı */

.workspace-container{position:relative;background:#f9f9fb;overflow:hidden;touch-action:none;cursor:grab}

.workspace-container:active{cursor:grabbing}

.workspace-canvas{position:absolute;top:0;left:0;width:100%;height:100%;transform-origin:0 0}


/* Yakınlaştırma (Zoom) Kontrolleri */

.zoom-controls{position:absolute;bottom:12px;right:12px;display:flex;gap:4px;background:white;padding:3px;border-radius:16px;box-shadow:0 2px 6px rgba(0,0,0,0.15);z-index:15}

.zoom-btn{width:26px;height:26px;border-radius:50%;border:none;background:#f0f0f5;color:#575e75;font-weight:bold;font-size:13px;cursor:pointer;display:flex;align-items:center;justify-content:center}

.zoom-btn:hover{background:#e2e2e8}


/* Tuval üzerindeki blok grupları */

.canvas-block-group{position:absolute;display:flex;flex-direction:column;align-items:flex-start;z-index:5}

.canvas-block-group .block{margin-bottom:-3px;cursor:move}

.canvas-block-group .block .remove-btn{margin-left:6px;background:rgba(0,0,0,0.2);border:none;color:white;border-radius:50%;width:14px;height:14px;font-size:9px;cursor:pointer;display:flex;align-items:center;justify-content:center}


/* Sağ Panel: Sahne ve Kuklalar */

.right-panel{background:#ffffff;border-left:1px solid #d9d9d9;display:flex;flex-direction:column;height:100%}

.stage-wrap{padding:8px;background:#f9f9fb;border-bottom:1px solid #e0e0e0}

.stage-header{display:flex;justify-content:space-between;font-weight:bold;font-size:11px;color:#575e75;margin-bottom:4px}

.stage{width:100%;aspect-ratio:4/3;background:#ffffff;border:2px solid #e0e0e0;border-radius:6px;position:relative;overflow:hidden;box-shadow:inset 0 0 8px rgba(0,0,0,0.05)}

.sprite-element{position:absolute;font-size:36px;transform:translate(-50%,-50%);user-select:none;transition:none;pointer-events:none}

.speech-bubble{position:absolute;background:white;border:2px solid #575e75;border-radius:10px;padding:3px 6px;font-size:10px;font-weight:bold;white-space:nowrap;transform:translate(-50%,-100%);top:-8px;left:50%;box-shadow:0 2px 4px rgba(0,0,0,0.1);display:none}

.speech-bubble::after{content:'';position:absolute;bottom:-5px;left:50%;transform:translateX(-50%);border-width:5px 5px 0;border-style:solid;border-color:white transparent;display:block;width:0}


/* Kukla Yönetim Paneli */

.sprites-manager{flex:1;display:flex;flex-direction:column;padding:8px;overflow:hidden;position:relative}

.sprites-header{font-size:11px;font-weight:bold;color:#575e75;margin-bottom:6px;display:flex;justify-content:space-between;align-items:center}

.sprites-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(58px,1fr));gap:6px;overflow-y:auto;flex:1;align-content:start}

.sprite-card{border:2px solid #e0e0e0;border-radius:6px;padding:6px;display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer;background:#f9f9fb;position:relative}

.sprite-card.active{border-color:#4c97ff;background:#e9f1ff}

.sprite-card .icon{font-size:22px}

.sprite-card .name{font-size:10px;font-weight:bold;color:#575e75}

.sprite-card .del{position:absolute;top:-3px;right:-3px;background:#ff6680;color:white;border:none;border-radius:50%;width:15px;height:15px;font-size:9px;cursor:pointer;display:none;align-items:center;justify-content:center}

.sprite-card:hover .del{display:flex}


.add-sprite-btn{position:absolute;bottom:8px;right:8px;width:36px;height:36px;border-radius:50%;background:#4c97ff;color:white;border:none;font-size:18px;cursor:pointer;box-shadow:0 3px 8px rgba(76,151,255,0.4);display:flex;align-items:center;justify-content:center;transition:transform 0.2s}

.add-sprite-btn:hover{transform:scale(1.08)}


/* Modal Kukla Seçici */

.modal-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.5);display:none;align-items:center;justify-content:center;z-index:100}

.modal{background:white;border-radius:10px;width:90%;max-width:350px;padding:12px;box-shadow:0 8px 20px rgba(0,0,0,0.2)}

.modal-title{font-weight:bold;font-size:14px;color:#575e75;margin-bottom:10px}

.animal-selector{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:220px;overflow-y:auto}

.animal-option{border:1px solid #e0e0e0;border-radius:6px;padding:8px;font-size:24px;text-align:center;cursor:pointer;transition:background 0.2s}

.animal-option:hover{background:#e9f1ff;border-color:#4c97ff}


.console{border-top:1px solid #e0e0e0;padding:6px 10px;font-size:10px;color:#666;background:#f9f9fb;max-height:50px;overflow-y:auto}


@media(max-width:850px){

  main{grid-template-columns:160px 1fr 210px}

}

</style>

</head>

<body>


<header>

  <div class="brand">🟣 Mini Scratch 3.0</div>

  <button class="run" id="btnRun">▶ Yeşil Bayrak</button>

  <button class="stop" id="btnStop">⏹ Durdur</button>

  <button class="clear" id="btnClear">Temizle</button>

  <button class="download" id="btnDownload">💾 Projeyi İndir</button>

</header>


<main>

  <!-- SOL PANEL: KATEGORİ VE PALET -->

  <section class="left-panel">

    <div class="categories-bar">

      <button class="cat-btn motion active" data-cat="motion"><div class="cat-dot"></div>Hareket</button>

      <button class="cat-btn looks" data-cat="looks"><div class="cat-dot"></div>Görünüm</button>

      <button class="cat-btn events" data-cat="events"><div class="cat-dot"></div>Olaylar</button>

      <button class="cat-btn control" data-cat="control"><div class="cat-dot"></div>Kontrol</button>

      <button class="cat-btn sound" data-cat="sound"><div class="cat-dot"></div>Ses</button>

    </div>

    <div class="palette-area" id="paletteArea"></div>

  </section>


  <!-- ORTA PANEL: AÇIK GRİ SONSUZ KOD ALANI -->

  <section class="workspace-container" id="workspaceContainer">

    <div class="workspace-canvas" id="workspaceCanvas"></div>

    <div class="zoom-controls">

      <button class="zoom-btn" id="zoomIn">+</button>

      <button class="zoom-btn" id="zoomReset">=</button>

      <button class="zoom-btn" id="zoomOut">-</button>

    </div>

  </section>


  <!-- SAĞ PANEL: SAHNE VE KUKLALAR -->

  <section class="right-panel">

    <div class="stage-wrap">

      <div class="stage-header"><span>🎭 Sahne</span><small>480 × 360</small></div>

      <div class="stage" id="stage"></div>

    </div>

    

    <div class="sprites-manager">

      <div class="sprites-header"><span>🐾 Kuklalar</span><small id="activeSpriteName">Kedi</small></div>

      <div class="sprites-grid" id="spritesGrid"></div>

      <button class="add-sprite-btn" id="btnAddSpriteModal" title="Kukla Ekle">+</button>

    </div>

    

    <div class="console" id="console">Hazır! Kukla seç ve kod bloklarını sürükle.</div>

  </section>

</main>


<!-- KUKLA EKLEME MODAL PENCERESİ -->

<div class="modal-overlay" id="modalOverlay">

  <div class="modal">

    <div class="modal-title">Bir Kukla Seç</div>

    <div class="animal-selector" id="animalSelector"></div>

  </div>

</div>


<script>

const blockDefinitions = {

  motion: [

    { id: 'move', text: '10 adım git', type: 'b-motion', inputType: 'number', defaultValue: '10' },

    { id: 'turn', text: '15 derece dön', type: 'b-motion', inputType: 'number', defaultValue: '15' },

    { id: 'goto', text: 'x: 0 y: 0 git', type: 'b-motion', inputType: 'xy', defaultValue: '0,0' },

    { id: 'bounce', text: 'Kenara geldiyse zıpla', type: 'b-motion' }

  ],

  looks: [

    { id: 'say', text: 'Merhaba! de', type: 'b-looks', inputType: 'text', defaultValue: 'Merhaba!' },

    { id: 'size', text: 'Boyutu %100 yap', type: 'b-looks', inputType: 'number', defaultValue: '100' },

    { id: 'hide', text: 'Gizlen', type: 'b-looks' },

    { id: 'show', text: 'Görün', type: 'b-looks' }

  ],

  events: [

    { id: 'flag', text: '🟢 Yeşil bayrak tıklanınca', type: 'b-events block-hat' }

  ],

  control: [

    { id: 'repeat', text: '3 kez tekrarla', type: 'b-control', inputType: 'number', defaultValue: '3' },

    { id: 'wait', text: '1 saniye bekle', type: 'b-control', inputType: 'number', defaultValue: '1' }

  ],

  sound: [

    { id: 'sound', text: 'Ses çal', type: 'b-sound' }

  ]

};


const animals = ['🐱','🐶','🐸','🦊','🐼','🐧','👾','🦄','🐰','🦁','🐵','🐯'];


let sprites = [

  { id: 'sprite_1', name: 'Kedi', icon: '🐱', x: 50, y: 50, angle: 0, size: 40, visible: true, speech: '', panX: 0, panY: 0, zoom: 1, stacks: [] }

];

let activeSpriteId = 'sprite_1';

let activeCategory = 'motion';

let isGlobalRunning = false;

let globalExecutionToken = 0;


const paletteArea = document.getElementById('paletteArea');

const workspaceContainer = document.getElementById('workspaceContainer');

const workspaceCanvas = document.getElementById('workspaceCanvas');

const stage = document.getElementById('stage');

const spritesGrid = document.getElementById('spritesGrid');

const consoleEl = document.getElementById('console');

const modalOverlay = document.getElementById('modalOverlay');

const animalSelector = document.getElementById('animalSelector');


function init() {

  renderCategories();

  renderPalette();

  renderSpritesGrid();

  renderStage();

  renderWorkspace();

  setupPanAndZoom();

  setupModal();

}


function renderCategories() {

  document.querySelectorAll('.cat-btn').forEach(btn => {

    btn.onclick = () => {

      document.querySelectorAll('.cat-btn').forEach(b => b.classList.remove('active'));

      btn.classList.add('active');

      activeCategory = btn.dataset.cat;

      renderPalette();

    };

  });

}


function renderPalette() {

  paletteArea.innerHTML = '';

  const defs = blockDefinitions[activeCategory] || [];

  defs.forEach(def => {

    const el = createBlockElement(def, true);

    paletteArea.appendChild(el);

  });

}


function createBlockElement(def, isPalette = false, blockData = null) {

  const el = document.createElement('div');

  el.className = `block ${def.type}`;

  

  const span = document.createElement('span');

  span.textContent = def.text.replace(/10|15|0,0|Merhaba!|100|3|1/, '');

  el.appendChild(span);


  let input = null;

  if (def.inputType) {

    input = document.createElement('input');

    input.value = blockData ? blockData.val : def.defaultValue;

    input.onclick = (e) => e.stopPropagation();

    input.oninput = (e) => { if(blockData) blockData.val = e.target.value; };

    el.appendChild(input);

  }


  if (isPalette) {

    setupPaletteDrag(el, def);

  }

  return el;

}


function setupPaletteDrag(el, def) {

  el.onpointerdown = (e) => {

    e.preventDefault();

    const activeSprite = getActiveSprite();

    const rect = workspaceContainer.getBoundingClientRect();

    const canvasX = (e.clientX - rect.left - activeSprite.panX) / activeSprite.zoom;

    const canvasY = (e.clientY - rect.top - activeSprite.panY) / activeSprite.zoom;


    const newBlock = { id: def.id, val: def.defaultValue || '' };

    const newStack = { x: canvasX, y: canvasY, blocks: [newBlock] };

    activeSprite.stacks.push(newStack);

    

    renderWorkspace();

    const groupEl = workspaceCanvas.lastElementChild;

    startGroupDrag(e, activeSprite, newStack, groupEl);

  };

}


function setupPanAndZoom() {

  let isPanning = false;

  let startX, startY;


  workspaceContainer.onpointerdown = (e) => {

    if (e.target === workspaceContainer || e.target === workspaceCanvas) {

      isPanning = true;

      startX = e.clientX;

      startY = e.clientY;

    }

  };


  window.addEventListener('pointermove', (e) => {

    if (isPanning) {

      const activeSprite = getActiveSprite();

      activeSprite.panX += e.clientX - startX;

      activeSprite.panY += e.clientY - startY;

      startX = e.clientX;

      startY = e.clientY;

      applyCanvasTransform();

    }

  });


  window.addEventListener('pointerup', () => { isPanning = false; });


  document.getElementById('zoomIn').onclick = () => changeZoom(0.1);

  document.getElementById('zoomOut').onclick = () => changeZoom(-0.1);

  document.getElementById('zoomReset').onclick = () => {

    const s = getActiveSprite();

    s.zoom = 1; s.panX = 0; s.panY = 0;

    applyCanvasTransform();

  };

}


function changeZoom(delta) {

  const s = getActiveSprite();

  s.zoom = Math.max(0.4, Math.min(1.8, s.zoom + delta));

  applyCanvasTransform();

}


function applyCanvasTransform() {

  const s = getActiveSprite();

  workspaceCanvas.style.transform = `translate(${s.panX}px, ${s.panY}px) scale(${s.zoom})`;

}


function renderWorkspace() {

  workspaceCanvas.innerHTML = '';

  const sprite = getActiveSprite();

  applyCanvasTransform();


  sprite.stacks.forEach((stack, stackIdx) => {

    const groupEl = document.createElement('div');

    groupEl.className = 'canvas-block-group';

    groupEl.style.left = stack.x + 'px';

    groupEl.style.top = stack.y + 'px';


    stack.blocks.forEach((bData, bIdx) => {

      const def = findBlockDef(bData.id);

      const bEl = createBlockElement(def, false, bData);

      

      const delBtn = document.createElement('button');

      delBtn.className = 'remove-btn';

      delBtn.textContent = '×';

      delBtn.onclick = (e) => {

        e.stopPropagation();

        stack.blocks.splice(bIdx, 1);

        if (stack.blocks.length === 0) sprite.stacks.splice(stackIdx, 1);

        renderWorkspace();

      };

      bEl.appendChild(delBtn);

      groupEl.appendChild(bEl);

    });


    groupEl.onpointerdown = (e) => {

      e.stopPropagation();

      startGroupDrag(e, sprite, stack, groupEl);

    };


    workspaceCanvas.appendChild(groupEl);

  });

}


function startGroupDrag(e, sprite, stack, groupEl) {

  let startX = e.clientX;

  let startY = e.clientY;


  const onMove = (me) => {

    const dx = (me.clientX - startX) / sprite.zoom;

    const dy = (me.clientY - startY) / sprite.zoom;

    stack.x += dx;

    stack.y += dy;

    groupEl.style.left = stack.x + 'px';

    groupEl.style.top = stack.y + 'px';

    startX = me.clientX;

    startY = me.clientY;

  };


  const onUp = () => {

    window.removeEventListener('pointermove', onMove);

    window.removeEventListener('pointerup', onUp);

    checkSnap(sprite, stack);

    renderWorkspace();

  };


  window.addEventListener('pointermove', onMove);

  window.addEventListener('pointerup', onUp);

}


function checkSnap(sprite, targetStack) {

  const SNAP_DIST = 30;

  for (let otherStack of sprite.stacks) {

    if (otherStack === targetStack) continue;

    const dx = Math.abs(otherStack.x - targetStack.x);

    const dy = Math.abs((otherStack.y + otherStack.blocks.length * 28) - targetStack.y);


    if (dx < SNAP_DIST && dy < SNAP_DIST) {

      otherStack.blocks.push(...targetStack.blocks);

      const idx = sprite.stacks.indexOf(targetStack);

      if (idx > -1) sprite.stacks.splice(idx, 1);

      break;

    }

  }

}


function getActiveSprite() {

  return sprites.find(s => s.id === activeSpriteId) || sprites[0];

}


function renderSpritesGrid() {

  spritesGrid.innerHTML = '';

  sprites.forEach(s => {

    const card = document.createElement('div');

    card.className = `sprite-card ${s.id === activeSpriteId ? 'active' : ''}`;

    card.innerHTML = `<div class="icon">${s.icon}</div><div class="name">${s.name}</div>`;

    

    if (sprites.length > 1) {

      const del = document.createElement('button');

      del.className = 'del';

      del.textContent = '×';

      del.onclick = (e) => {

        e.stopPropagation();

        sprites = sprites.filter(x => x.id !== s.id);

        if (activeSpriteId === s.id) activeSpriteId = sprites[0].id;

        renderSpritesGrid();

        renderStage();

        renderWorkspace();

      };

      card.appendChild(del);

    }


    card.onclick = () => {

      activeSpriteId = s.id;

      document.getElementById('activeSpriteName').textContent = s.name;

      renderSpritesGrid();

      renderWorkspace();

    };

    spritesGrid.appendChild(card);

  });

}


function renderStage() {

  stage.innerHTML = '';

  sprites.forEach(s => {

    const el = document.createElement('div');

    el.className = 'sprite-element';

    el.style.left = s.x + '%';

    el.style.top = s.y + '%';

    el.style.fontSize = s.size + 'px';

    el.style.transform = `translate(-50%, -50%) rotate(${s.angle}deg)`;

    el.style.display = s.visible ? 'block' : 'none';

    el.textContent = s.icon;


    if (s.speech) {

      const bubble = document.createElement('div');

      bubble.className = 'speech-bubble';

      bubble.style.display = 'block';

      bubble.textContent = s.speech;

      el.appendChild(bubble);

    }


    stage.appendChild(el);

  });

}


function setupModal() {

  const btn = document.getElementById('btnAddSpriteModal');

  btn.onclick = () => modalOverlay.style.display = 'flex';

  modalOverlay.onclick = (e) => { if(e.target === modalOverlay) modalOverlay.style.display = 'none'; };


  animalSelector.innerHTML = '';

  animals.forEach(icon => {

    const opt = document.createElement('div');

    opt.className = 'animal-option';

    opt.textContent = icon;

    opt.onclick = () => {

      const newSprite = {

        id: 'sprite_' + Date.now(),

        name: 'Kukla ' + (sprites.length + 1),

        icon: icon,

        x: 30 + Math.random() * 40,

        y: 30 + Math.random() * 40,

        angle: 0,

        size: 40,

        visible: true,

        speech: '',

        panX: 0, panY: 0, zoom: 1,

        stacks: []

      };

      sprites.push(newSprite);

      activeSpriteId = newSprite.id;

      modalOverlay.style.display = 'none';

      renderSpritesGrid();

      renderStage();

      renderWorkspace();

    };

    animalSelector.appendChild(opt);

  });

}


const sleep = ms => new Promise(r => setTimeout(r, ms));


async function runProgram() {

  isGlobalRunning = true;

  globalExecutionToken++;

  const token = globalExecutionToken;

  log('🟢 Program başlatıldı...');


  const promises = sprites.map(sprite => executeSpriteStacks(sprite, token));

  await Promise.all(promises);

  

  if (token === globalExecutionToken) {

    isGlobalRunning = false;

    log('⏹ Program tamamlandı.');

  }

}


async function executeSpriteStacks(sprite, token) {

  for (let stack of sprite.stacks) {

    if (!stack.blocks.length || stack.blocks[0].id !== 'flag') continue;

    

    for (let bData of stack.blocks) {

      if (!isGlobalRunning || token !== globalExecutionToken) break;

      await executeBlock(sprite, bData, token);

      renderStage();

      await sleep(150);

    }

  }

}


async function executeBlock(sprite, bData, token) {

  const val = bData.val;

  const num = Number(val);


  switch(bData.id) {

    case 'move':

      const rad = sprite.angle * Math.PI / 180;

      sprite.x = Math.max(5, Math.min(95, sprite.x + Math.cos(rad) * (num || 10) / 4));

      sprite.y = Math.max(5, Math.min(95, sprite.y + Math.sin(rad) * (num || 10) / 4));

      break;

    case 'turn':

      sprite.angle += (num || 15);

      break;

    case 'goto':

      const parts = (val || '0,0').split(',');

      sprite.x = Math.max(5, Math.min(95, 50 + Number(parts[0] || 0) / 5));

      sprite.y = Math.max(5, Math.min(95, 50 - Number(parts[1] || 0) / 5));

      break;

    case 'bounce':

      if (sprite.x >= 90 || sprite.x <= 10) sprite.angle = 180 - sprite.angle;

      if (sprite.y >= 90 || sprite.y <= 10) sprite.angle = -sprite.angle;

      break;

    case 'say':

      sprite.speech = val;

      renderStage();

      await sleep(1500);

      sprite.speech = '';

      break;

    case 'size':

      sprite.size = Math.max(14, Math.min(100, num || 100)) * 0.4;

      break;

    case 'hide': sprite.visible = false; break;

    case 'show': sprite.visible = true; break;

    case 'repeat': break;

    case 'wait':

      await sleep((num || 1) * 1000);

      break;

    case 'sound':

      playBeep();

      log(`♪ ${sprite.name} ses çıkardı!`);

      break;

  }

}


function playBeep() {

  try {

    const ctx = new (window.AudioContext || window.webkitAudioContext)();

    const osc = ctx.createOscillator();

    const gain = ctx.createGain();

    osc.frequency.value = 440;

    gain.gain.value = 0.1;

    osc.connect(gain);

    gain.connect(ctx.destination);

    osc.start();

    osc.stop(ctx.currentTime + 0.15);

  } catch(e){}

}


function findBlockDef(id) {

  for (let cat of Object.values(blockDefinitions)) {

    const found = cat.find(b => b.id === id);

    if (found) return found;

  }

  return { id, text: id, type: 'b-motion' };

}


function log(msg) { consoleEl.textContent = msg; }


document.getElementById('btnRun').onclick = runProgram;

document.getElementById('btnStop').onclick = () => {

  isGlobalRunning = false;

  globalExecutionToken++;

  log('⏹ Durduruldu.');

};

document.getElementById('btnClear').onclick = () => {

  const s = getActiveSprite();

  s.stacks = [];

  renderWorkspace();

  log('Kod alanı temizlendi.');

};


document.getElementById('btnDownload').onclick = () => {

  const htmlContent = "<!doctype html>\n" + document.documentElement.outerHTML;

  const blob = new Blob([htmlContent], { type: 'text/html' });

  const url = URL.createObjectURL(blob);

  const a = document.createElement('a');

  a.href = url;

  a.download = 'scratch_projesi.html';

  a.click();

  URL.revokeObjectURL(url);

  log('💾 Proje başarıyla indirildi!');

};


window.onload = init;

</script>

</body>

</html>


Hosted & Compiled with HtmlRunner.com