turboned-developent / index.html
DeepSiteOptional's picture
Add 3 files
2ddb858 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TurbONED - Creative Coding Platform</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');
body {
font-family: 'Roboto', sans-serif;
background-color: #f0f4f8;
margin: 0;
padding: 0;
overflow-x: hidden;
}
.gradient-bg {
background: linear-gradient(135deg, #6e45e2 0%, #88d3ce 50%, #f9d423 100%);
}
.block {
background-color: rgba(255, 255, 255, 0.9);
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 10px;
margin: 5px;
cursor: move;
user-select: none;
transition: all 0.2s;
position: relative;
}
.block:hover {
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
}
.block.active {
animation: pulse 1s infinite alternate;
box-shadow: 0 0 10px rgba(255, 165, 0, 0.7);
}
@keyframes pulse {
from {
box-shadow: 0 0 5px rgba(255, 165, 0, 0.7);
}
to {
box-shadow: 0 0 15px rgba(255, 0, 0, 0.7);
}
}
.workspace {
background-color: white;
border-radius: 10px;
min-height: 400px;
position: relative;
overflow: hidden;
}
.sprite {
width: 60px;
height: 60px;
border-radius: 8px;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.sprite:hover {
transform: scale(1.05);
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
#stage {
background-color: #f0f0f0;
border-radius: 8px;
overflow: hidden;
position: relative;
}
.draggable {
position: absolute;
cursor: move;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background-color: white;
padding: 20px;
border-radius: 10px;
max-width: 500px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
}
.costume-thumbnail {
width: 80px;
height: 80px;
border-radius: 8px;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
margin: 5px;
cursor: pointer;
transition: all 0.2s;
}
.costume-thumbnail:hover {
transform: scale(1.05);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.sound-item {
padding: 10px;
border-radius: 8px;
background-color: #f0f0f0;
margin: 5px 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.dragging {
opacity: 0.5;
}
.dropzone {
min-height: 100px;
border: 2px dashed #ccc;
border-radius: 8px;
padding: 10px;
margin: 10px 0;
text-align: center;
}
.dropzone.highlight {
border-color: #6e45e2;
background-color: rgba(110, 69, 226, 0.1);
}
.block-container {
position: relative;
margin: 10px 0;
}
.block-connector {
width: 100%;
height: 15px;
background-color: rgba(110, 69, 226, 0.2);
border-radius: 0 0 8px 8px;
margin-top: -5px;
cursor: pointer;
}
.block-connector:hover {
background-color: rgba(110, 69, 226, 0.4);
}
.block-connector-top {
width: 100%;
height: 15px;
background-color: rgba(110, 69, 226, 0.2);
border-radius: 8px 8px 0 0;
margin-bottom: -5px;
cursor: pointer;
}
.block-connector-top:hover {
background-color: rgba(110, 69, 226, 0.4);
}
.connected-block {
margin-top: -10px;
}
.flag-btn {
position: absolute;
top: 10px;
left: 10px;
z-index: 10;
background-color: #f9d423;
color: white;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.flag-btn:hover {
transform: scale(1.1);
}
.block-slot {
background-color: rgba(110, 69, 226, 0.1);
border-radius: 4px;
padding: 5px;
margin: 5px 0;
min-height: 20px;
}
.block-slot.highlight {
background-color: rgba(110, 69, 226, 0.3);
border: 1px dashed #6e45e2;
}
.creator-credit {
position: fixed;
bottom: 10px;
right: 10px;
background-color: rgba(255, 255, 255, 0.8);
padding: 5px 10px;
border-radius: 15px;
font-size: 12px;
z-index: 100;
}
.block-options {
position: absolute;
top: 100%;
left: 0;
background-color: white;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
z-index: 100;
padding: 10px;
min-width: 200px;
display: none;
}
.block-option {
padding: 8px;
border-radius: 4px;
cursor: pointer;
margin-bottom: 5px;
}
.block-option:hover {
background-color: #f0f4f8;
}
.block-with-options {
position: relative;
}
.block-options-container {
display: none;
position: absolute;
top: 0;
left: 100%;
background-color: white;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
z-index: 100;
padding: 10px;
min-width: 200px;
}
.block-options-container.show {
display: block;
}
/* New styles for enhanced block selection */
.block-selection-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
z-index: 2000;
display: flex;
justify-content: center;
align-items: center;
display: none;
}
.block-selection-container {
background-color: white;
border-radius: 12px;
width: 80%;
max-width: 800px;
max-height: 80vh;
overflow-y: auto;
padding: 20px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.block-selection-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.block-selection-title {
font-size: 1.5rem;
font-weight: bold;
color: #6e45e2;
}
.block-selection-close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: #666;
}
.block-selection-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 15px;
}
.block-selection-item {
background-color: #f8f9fa;
border-radius: 8px;
padding: 15px;
cursor: pointer;
transition: all 0.2s;
border: 2px solid transparent;
}
.block-selection-item:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
border-color: #6e45e2;
}
.block-selection-item.active {
border-color: #6e45e2;
background-color: #e9e0ff;
}
.block-selection-icon {
font-size: 1.5rem;
margin-bottom: 10px;
color: #6e45e2;
}
.block-selection-name {
font-weight: 500;
margin-bottom: 5px;
}
.block-selection-description {
font-size: 0.8rem;
color: #666;
}
.block-selection-footer {
display: flex;
justify-content: space-between;
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #eee;
}
.block-selection-btn {
padding: 8px 20px;
border-radius: 6px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.block-selection-back {
background-color: #f0f0f0;
color: #333;
}
.block-selection-back:hover {
background-color: #e0e0e0;
}
.block-selection-confirm {
background-color: #6e45e2;
color: white;
}
.block-selection-confirm:hover {
background-color: #5a35d1;
}
/* Category tabs */
.block-category-tabs {
display: flex;
margin-bottom: 15px;
border-bottom: 1px solid #eee;
}
.block-category-tab {
padding: 8px 15px;
margin-right: 5px;
cursor: pointer;
border-bottom: 3px solid transparent;
font-weight: 500;
color: #666;
}
.block-category-tab.active {
color: #6e45e2;
border-bottom-color: #6e45e2;
}
</style>
</head>
<body class="min-h-screen">
<!-- Main Layout -->
<div class="flex flex-col min-h-screen">
<!-- Header -->
<header class="gradient-bg text-white shadow-lg">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center">
<i class="fas fa-code text-3xl mr-3"></i>
<h1 class="text-2xl font-bold">TurbONED</h1>
</div>
<div class="flex items-center space-x-4">
<button id="loginBtn" class="bg-white text-purple-600 px-4 py-1 rounded-lg hover:bg-gray-100 transition">Login</button>
<button id="registerBtn" class="bg-white text-blue-600 px-4 py-1 rounded-lg hover:bg-gray-100 transition">Register</button>
<div id="userMenu" class="hidden">
<div class="relative">
<button class="flex items-center space-x-2 bg-white bg-opacity-20 px-4 py-1 rounded-lg hover:bg-opacity-30 transition">
<span id="usernameDisplay">User</span>
<i class="fas fa-chevron-down"></i>
</button>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-grow container mx-auto px-4 py-6">
<div class="flex flex-col lg:flex-row gap-6">
<!-- Left Sidebar - Blocks -->
<div class="w-full lg:w-1/4 bg-white rounded-xl shadow-md p-4">
<div class="flex mb-4 border-b pb-2">
<button onclick="changeTab('blocks')" class="tab-btn active px-4 py-2 font-medium text-purple-600 border-b-2 border-purple-600">Blocks</button>
<button onclick="changeTab('costumes')" class="tab-btn px-4 py-2 font-medium text-blue-600">Costumes</button>
<button onclick="changeTab('sounds')" class="tab-btn px-4 py-2 font-medium text-yellow-600">Sounds</button>
</div>
<div id="blocks" class="tab-content active">
<h3 class="font-bold text-lg mb-3 text-purple-700">Events</h3>
<div class="block block-with-options" draggable="true" data-type="events" data-block="whenFlag" onclick="showBlockSelection('whenFlag')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-green-500 mr-2"></div>
<span>when flag clicked</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
<div class="block-connector"></div>
</div>
<div class="block block-with-options" draggable="true" data-type="events" data-block="whenKey" onclick="showBlockSelection('whenKey')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-green-500 mr-2"></div>
<span>when key pressed</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
<div class="block-connector"></div>
</div>
<h3 class="font-bold text-lg mt-4 mb-3 text-purple-700">Motion</h3>
<div class="block block-with-options" draggable="true" data-type="motion" data-block="move" onclick="showBlockSelection('move')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-purple-500 mr-2"></div>
<span>move steps</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
</div>
<div class="block block-with-options" draggable="true" data-type="motion" data-block="turn" onclick="showBlockSelection('turn')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-purple-500 mr-2"></div>
<span>turn degrees</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
</div>
<div class="block block-with-options" draggable="true" data-type="motion" data-block="goTo" onclick="showBlockSelection('goTo')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-purple-500 mr-2"></div>
<span>go to position</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
</div>
<h3 class="font-bold text-lg mt-4 mb-3 text-blue-600">Looks</h3>
<div class="block block-with-options" draggable="true" data-type="looks" data-block="say" onclick="showBlockSelection('say')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-blue-500 mr-2"></div>
<span>say message</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
</div>
<div class="block" draggable="true" data-type="looks" data-block="changeCostume">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-blue-500 mr-2"></div>
<span>next costume</span>
</div>
</div>
<div class="block block-with-options" draggable="true" data-type="looks" data-block="changeSize" onclick="showBlockSelection('changeSize')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-blue-500 mr-2"></div>
<span>change size by</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
</div>
<h3 class="font-bold text-lg mt-4 mb-3 text-yellow-600">Sound</h3>
<div class="block block-with-options" draggable="true" data-type="sound" data-block="playSound" onclick="showBlockSelection('playSound')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-yellow-500 mr-2"></div>
<span>play sound</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
</div>
<div class="block" draggable="true" data-type="sound" data-block="stopSound">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-yellow-500 mr-2"></div>
<span>stop all sounds</span>
</div>
</div>
<h3 class="font-bold text-lg mt-4 mb-3 text-red-600">Control</h3>
<div class="block block-with-options" draggable="true" data-type="control" data-block="wait" onclick="showBlockSelection('wait')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-red-500 mr-2"></div>
<span>wait seconds</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
</div>
<div class="block block-with-options" draggable="true" data-type="control" data-block="repeat" onclick="showBlockSelection('repeat')">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-red-500 mr-2"></div>
<span>repeat times</span>
<i class="fas fa-chevron-down ml-2 text-gray-500"></i>
</div>
<div class="block-slot"></div>
<div class="block-connector"></div>
</div>
<h3 class="font-bold text-lg mt-4 mb-3 text-indigo-600">Conditionals</h3>
<div class="block" draggable="true" data-type="control" data-block="if">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-indigo-500 mr-2"></div>
<span>if &lt;condition&gt; then</span>
</div>
<div class="block-slot"></div>
<div class="block-connector"></div>
</div>
</div>
<div id="costumes" class="tab-content">
<div class="flex flex-wrap justify-center">
<div class="costume-thumbnail m-2">
<i class="fas fa-plus text-2xl text-gray-500"></i>
</div>
<div class="costume-thumbnail m-2">
<i class="fas fa-tshirt text-3xl text-purple-500"></i>
</div>
<div class="costume-thumbnail m-2">
<i class="fas fa-hat-wizard text-3xl text-blue-500"></i>
</div>
<div class="costume-thumbnail m-2">
<i class="fas fa-mask text-3xl text-yellow-500"></i>
</div>
</div>
</div>
<div id="sounds" class="tab-content">
<button class="w-full bg-gray-200 hover:bg-gray-300 py-2 rounded-lg mb-4">
<i class="fas fa-plus mr-2"></i> Add Sound
</button>
<div class="sound-item">
<div>
<i class="fas fa-music mr-2 text-purple-500"></i>
<span>Pop Sound</span>
</div>
<button class="bg-purple-100 text-purple-700 px-3 py-1 rounded-lg hover:bg-purple-200">
<i class="fas fa-play"></i>
</button>
</div>
</div>
</div>
<!-- Center - Workspace and Stage -->
<div class="w-full lg:w-2/4 flex flex-col gap-4">
<div class="workspace p-4" id="workspace">
<div class="flag-btn" onclick="runScripts()">
<i class="fas fa-flag"></i>
</div>
<p class="text-gray-500 text-center py-10">Drag blocks here to build your script</p>
</div>
<div id="stage" class="w-full h-64 relative">
<div id="currentSprite" class="draggable" style="left: 50%; top: 50%; transform: translate(-50%, -50%);">
<i class="fas fa-cat text-4xl text-purple-600"></i>
</div>
<button class="absolute bottom-2 right-2 bg-white bg-opacity-80 px-3 py-1 rounded-lg hover:bg-opacity-100">
<i class="fas fa-image mr-1"></i> Background
</button>
</div>
<div class="flex justify-center space-x-4">
<button class="bg-green-500 text-white px-4 py-2 rounded-lg hover:bg-green-600" onclick="runScripts()">
<i class="fas fa-play mr-2"></i> Run
</button>
<button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600" onclick="stopScripts()">
<i class="fas fa-stop mr-2"></i> Stop
</button>
</div>
</div>
<!-- Right Sidebar - Sprites -->
<div class="w-full lg:w-1/4 bg-white rounded-xl shadow-md p-4">
<div class="flex justify-between items-center mb-4">
<h2 class="font-bold text-lg">Sprites</h2>
<button class="bg-purple-100 text-purple-700 p-2 rounded-lg hover:bg-purple-200">
<i class="fas fa-plus"></i>
</button>
</div>
<div class="grid grid-cols-3 gap-3">
<div class="sprite bg-purple-100">
<i class="fas fa-cat text-2xl text-purple-600"></i>
</div>
<div class="sprite bg-blue-100">
<i class="fas fa-dog text-2xl text-blue-600"></i>
</div>
<div class="sprite bg-yellow-100">
<i class="fas fa-user text-2xl text-yellow-600"></i>
</div>
</div>
<div class="mt-6">
<div class="flex mb-4 border-b pb-2">
<button onclick="changeRightTab('properties')" class="tab-btn active px-4 py-2 font-medium text-purple-600 border-b-2 border-purple-600">Properties</button>
<button onclick="changeRightTab('multiplayer')" class="tab-btn px-4 py-2 font-medium text-blue-600">Multiplayer</button>
<button onclick="changeRightTab('developers')" class="tab-btn px-4 py-2 font-medium text-yellow-600">Developers</button>
</div>
<div id="properties" class="tab-content active">
<div class="mb-4">
<label class="block text-gray-700 mb-1">Sprite Name</label>
<input type="text" value="Sprite1" class="w-full px-3 py-2 border rounded-lg">
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">Position</label>
<div class="flex space-x-2">
<input type="number" value="0" class="w-1/2 px-3 py-2 border rounded-lg" placeholder="X">
<input type="number" value="0" class="w-1/2 px-3 py-2 border rounded-lg" placeholder="Y">
</div>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">Size</label>
<input type="range" min="10" max="200" value="100" class="w-full">
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">Direction</label>
<input type="range" min="0" max="360" value="90" class="w-full">
</div>
</div>
<div id="multiplayer" class="tab-content">
<div class="text-center py-4">
<i class="fas fa-users text-4xl text-blue-500 mb-3"></i>
<h3 class="font-bold text-lg mb-2">Multiplayer VEO1</h3>
<p class="text-gray-600 mb-4">Connect with friends to code together in real-time</p>
<button class="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 w-full">
<i class="fas fa-plug mr-2"></i> Connect
</button>
</div>
</div>
<div id="developers" class="tab-content">
<div class="text-center py-4">
<i class="fas fa-code text-4xl text-yellow-500 mb-3"></i>
<h3 class="font-bold text-lg mb-2">TurbONED Developers</h3>
<div class="bg-yellow-100 p-3 rounded-lg mt-3">
<div class="font-semibold">Diamond5diamond</div>
<div class="text-sm text-gray-600">Lead Developer</div>
</div>
<p class="text-gray-600 mt-4">TurbONED is developed by a passionate team of coders who love creative programming.</p>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="gradient-bg text-white py-4">
<div class="container mx-auto px-4 text-center">
<p>&copy; 2023 TurbONED - A creative coding platform</p>
<div class="flex justify-center space-x-4 mt-2">
<a href="#" class="hover:text-gray-200"><i class="fab fa-twitter"></i></a>
<a href="#" class="hover:text-gray-200"><i class="fab fa-github"></i></a>
<a href="#" class="hover:text-gray-200"><i class="fab fa-discord"></i></a>
</div>
</div>
</footer>
</div>
<!-- Block Selection Overlay -->
<div class="block-selection-overlay" id="blockSelectionOverlay">
<div class="block-selection-container">
<div class="block-selection-header">
<div class="block-selection-title" id="blockSelectionTitle">Select Block Options</div>
<button class="block-selection-close" onclick="hideBlockSelection()">&times;</button>
</div>
<div class="block-category-tabs" id="blockCategoryTabs">
<div class="block-category-tab active" data-category="all">All</div>
<div class="block-category-tab" data-category="motion">Motion</div>
<div class="block-category-tab" data-category="looks">Looks</div>
<div class="block-category-tab" data-category="sound">Sound</div>
<div class="block-category-tab" data-category="control">Control</div>
</div>
<div class="block-selection-grid" id="blockSelectionGrid">
<!-- Blocks will be inserted here dynamically -->
</div>
<div class="block-selection-footer">
<button class="block-selection-btn block-selection-back" onclick="goBackInSelection()">
<i class="fas fa-arrow-left mr-2"></i> Back
</button>
<button class="block-selection-btn block-selection-confirm" onclick="confirmBlockSelection()">
Confirm Selection
</button>
</div>
</div>
</div>
<div class="creator-credit">
Created by Google Veo Generation
</div>
<script>
// Global variables
let currentUser = null;
let isRunning = false;
let activeScripts = [];
let draggedBlock = null;
let activeBlock = null;
let blockInstances = new Set();
let currentBlockType = null;
let selectedBlockOption = null;
let selectionHistory = [];
// Block options data
const blockOptions = {
whenFlag: [
{ name: "All Blocks", value: "all", description: "Execute all connected blocks", icon: "fa-code" },
{ name: "Motion Blocks", value: "motion", description: "Execute only motion blocks", icon: "fa-arrows-alt" },
{ name: "Looks Blocks", value: "looks", description: "Execute only looks blocks", icon: "fa-eye" },
{ name: "Sound Blocks", value: "sound", description: "Execute only sound blocks", icon: "fa-music" },
{ name: "Control Blocks", value: "control", description: "Execute only control blocks", icon: "fa-cogs" }
],
whenKey: [
{ name: "Space", value: "space", description: "Trigger when space key is pressed", icon: "fa-keyboard" },
{ name: "Up Arrow", value: "up", description: "Trigger when up arrow is pressed", icon: "fa-arrow-up" },
{ name: "Down Arrow", value: "down", description: "Trigger when down arrow is pressed", icon: "fa-arrow-down" },
{ name: "Left Arrow", value: "left", description: "Trigger when left arrow is pressed", icon: "fa-arrow-left" },
{ name: "Right Arrow", value: "right", description: "Trigger when right arrow is pressed", icon: "fa-arrow-right" }
],
move: [
{ name: "10 Steps", value: "10", description: "Move forward 10 steps", icon: "fa-arrow-right" },
{ name: "20 Steps", value: "20", description: "Move forward 20 steps", icon: "fa-arrow-right" },
{ name: "50 Steps", value: "50", description: "Move forward 50 steps", icon: "fa-arrow-right" },
{ name: "100 Steps", value: "100", description: "Move forward 100 steps", icon: "fa-arrow-right" },
{ name: "10 Steps Back", value: "-10", description: "Move backward 10 steps", icon: "fa-arrow-left" },
{ name: "20 Steps Back", value: "-20", description: "Move backward 20 steps", icon: "fa-arrow-left" },
{ name: "50 Steps Back", value: "-50", description: "Move backward 50 steps", icon: "fa-arrow-left" }
],
turn: [
{ name: "15 Degrees Right", value: "15", description: "Turn 15 degrees to the right", icon: "fa-redo" },
{ name: "30 Degrees Right", value: "30", description: "Turn 30 degrees to the right", icon: "fa-redo" },
{ name: "45 Degrees Right", value: "45", description: "Turn 45 degrees to the right", icon: "fa-redo" },
{ name: "90 Degrees Right", value: "90", description: "Turn 90 degrees to the right", icon: "fa-redo" },
{ name: "15 Degrees Left", value: "-15", description: "Turn 15 degrees to the left", icon: "fa-undo" },
{ name: "30 Degrees Left", value: "-30", description: "Turn 30 degrees to the left", icon: "fa-undo" }
],
goTo: [
{ name: "Random Position", value: "random", description: "Go to a random position on stage", icon: "fa-random" },
{ name: "Mouse Pointer", value: "mouse", description: "Go to current mouse position", icon: "fa-mouse-pointer" },
{ name: "Center", value: "center", description: "Go to center of stage", icon: "fa-crosshairs" }
],
say: [
{ name: "Hello!", value: "Hello!", description: "Say 'Hello!' for 2 seconds", icon: "fa-comment" },
{ name: "Hi there!", value: "Hi there!", description: "Say 'Hi there!' for 2 seconds", icon: "fa-comment" },
{ name: "Welcome!", value: "Welcome!", description: "Say 'Welcome!' for 2 seconds", icon: "fa-comment" }
],
changeSize: [
{ name: "Increase by 10", value: "10", description: "Increase size by 10%", icon: "fa-search-plus" },
{ name: "Increase by 20", value: "20", description: "Increase size by 20%", icon: "fa-search-plus" },
{ name: "Increase by 50", value: "50", description: "Increase size by 50%", icon: "fa-search-plus" },
{ name: "Decrease by 10", value: "-10", description: "Decrease size by 10%", icon: "fa-search-minus" }
],
playSound: [
{ name: "Pop Sound", value: "pop", description: "Play the pop sound effect", icon: "fa-volume-up" },
{ name: "Drum Sound", value: "drum", description: "Play the drum sound effect", icon: "fa-drum" },
{ name: "Bell Sound", value: "bell", description: "Play the bell sound effect", icon: "fa-bell" }
],
wait: [
{ name: "1 Second", value: "1", description: "Wait for 1 second", icon: "fa-clock" },
{ name: "2 Seconds", value: "2", description: "Wait for 2 seconds", icon: "fa-clock" },
{ name: "5 Seconds", value: "5", description: "Wait for 5 seconds", icon: "fa-clock" }
],
repeat: [
{ name: "5 Times", value: "5", description: "Repeat 5 times", icon: "fa-sync" },
{ name: "10 Times", value: "10", description: "Repeat 10 times", icon: "fa-sync" },
{ name: "20 Times", value: "20", description: "Repeat 20 times", icon: "fa-sync" }
]
};
// Initialize the app
document.addEventListener('DOMContentLoaded', function() {
// Setup block options
setupBlockOptions();
// Make all initial blocks draggable
const blocks = document.querySelectorAll('[draggable="true"]');
blocks.forEach(block => {
setupBlockDrag(block);
});
// Setup workspace drop zone
const workspace = document.getElementById('workspace');
workspace.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('bg-gray-100');
});
workspace.addEventListener('dragleave', function() {
this.classList.remove('bg-gray-100');
});
workspace.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('bg-gray-100');
if (draggedBlock) {
// Generate unique ID for the block
const blockId = 'block-' + Date.now() + '-' + Math.floor(Math.random() * 1000);
const newBlock = draggedBlock.cloneNode(true);
newBlock.id = blockId;
newBlock.style.position = 'absolute';
newBlock.style.left = (e.clientX - this.getBoundingClientRect().left - 50) + 'px';
newBlock.style.top = (e.clientY - this.getBoundingClientRect().top - 20) + 'px';
newBlock.style.margin = '0';
// Check if this block already exists in workspace
if (!blockInstances.has(blockId)) {
this.appendChild(newBlock);
blockInstances.add(blockId);
setupBlockDrag(newBlock);
setupBlockConnectors(newBlock);
setupBlockClick(newBlock);
// Remove "Drag blocks here" message if it exists
const message = this.querySelector('p.text-center');
if (message) {
message.remove();
}
}
}
});
// Make sprites draggable on stage
const sprite = document.getElementById('currentSprite');
makeDraggable(sprite);
// Setup click events for blocks in workspace
document.querySelectorAll('#workspace .block').forEach(block => {
setupBlockClick(block);
});
// Setup category tabs
document.querySelectorAll('.block-category-tab').forEach(tab => {
tab.addEventListener('click', function() {
document.querySelectorAll('.block-category-tab').forEach(t => {
t.classList.remove('active');
});
this.classList.add('active');
const category = this.getAttribute('data-category');
filterBlocksByCategory(category);
});
});
});
// Show block selection overlay
function showBlockSelection(blockType) {
currentBlockType = blockType;
selectionHistory = [];
const overlay = document.getElementById('blockSelectionOverlay');
const title = document.getElementById('blockSelectionTitle');
const grid = document.getElementById('blockSelectionGrid');
// Set title based on block type
switch(blockType) {
case 'whenFlag':
title.textContent = "When Flag Clicked - Select Blocks to Execute";
break;
case 'whenKey':
title.textContent = "When Key Pressed - Select Key";
break;
case 'move':
title.textContent = "Move Steps - Select Distance";
break;
case 'turn':
title.textContent = "Turn Degrees - Select Angle";
break;
case 'goTo':
title.textContent = "Go To - Select Position";
break;
case 'say':
title.textContent = "Say Message - Select Text";
break;
case 'changeSize':
title.textContent = "Change Size - Select Amount";
break;
case 'playSound':
title.textContent = "Play Sound - Select Sound";
break;
case 'wait':
title.textContent = "Wait - Select Duration";
break;
case 'repeat':
title.textContent = "Repeat - Select Times";
break;
default:
title.textContent = "Select Options";
}
// Clear the grid
grid.innerHTML = '';
// Add blocks to the grid
if (blockOptions[blockType]) {
blockOptions[blockType].forEach(option => {
const blockItem = document.createElement('div');
blockItem.className = 'block-selection-item';
blockItem.setAttribute('data-value', option.value);
blockItem.innerHTML = `
<div class="block-selection-icon">
<i class="fas ${option.icon}"></i>
</div>
<div class="block-selection-name">${option.name}</div>
<div class="block-selection-description">${option.description}</div>
`;
blockItem.addEventListener('click', function() {
document.querySelectorAll('.block-selection-item').forEach(item => {
item.classList.remove('active');
});
this.classList.add('active');
selectedBlockOption = this.getAttribute('data-value');
});
grid.appendChild(blockItem);
});
}
// Show the overlay
overlay.style.display = 'flex';
}
// Hide block selection overlay
function hideBlockSelection() {
document.getElementById('blockSelectionOverlay').style.display = 'none';
currentBlockType = null;
selectedBlockOption = null;
}
// Confirm block selection
function confirmBlockSelection() {
if (selectedBlockOption && activeBlock) {
const blockText = activeBlock.querySelector('span');
switch(currentBlockType) {
case 'whenFlag':
if (selectedBlockOption === 'all') {
blockText.textContent = 'when flag clicked (all blocks)';
} else {
blockText.textContent = `when flag clicked (${selectedBlockOption} blocks)`;
}
break;
case 'whenKey':
blockText.textContent = `when ${selectedBlockOption} pressed`;
break;
case 'move':
if (selectedBlockOption.startsWith('-')) {
blockText.textContent = `move ${selectedBlockOption.substring(1)} steps back`;
} else {
blockText.textContent = `move ${selectedBlockOption} steps`;
}
break;
case 'turn':
if (selectedBlockOption.startsWith('-')) {
blockText.textContent = `turn ${selectedBlockOption.substring(1)} degrees left`;
} else {
blockText.textContent = `turn ${selectedBlockOption} degrees right`;
}
break;
case 'goTo':
blockText.textContent = `go to ${selectedBlockOption}`;
break;
case 'say':
blockText.textContent = `say ${selectedBlockOption} for 2 seconds`;
break;
case 'changeSize':
blockText.textContent = `change size by ${selectedBlockOption}`;
break;
case 'playSound':
blockText.textContent = `play sound ${selectedBlockOption}`;
break;
case 'wait':
blockText.textContent = `wait ${selectedBlockOption} second${selectedBlockOption !== '1' ? 's' : ''}`;
break;
case 'repeat':
blockText.textContent = `repeat ${selectedBlockOption} times`;
break;
}
}
hideBlockSelection();
}
// Go back in selection
function goBackInSelection() {
// In this simple implementation, just hide the selection
hideBlockSelection();
}
// Filter blocks by category
function filterBlocksByCategory(category) {
if (category === 'all') {
document.querySelectorAll('.block-selection-item').forEach(item => {
item.style.display = 'block';
});
return;
}
document.querySelectorAll('.block-selection-item').forEach(item => {
// In a real implementation, you would filter based on actual categories
// For now, we'll just show all items
item.style.display = 'block';
});
}
// Setup block options functionality
function setupBlockOptions() {
document.querySelectorAll('.block-with-options').forEach(block => {
const optionsBtn = block.querySelector('.fa-chevron-down');
const blockType = block.getAttribute('data-block');
optionsBtn.addEventListener('click', function(e) {
e.stopPropagation();
activeBlock = block;
showBlockSelection(blockType);
});
});
}
// Setup block drag functionality
function setupBlockDrag(block) {
block.addEventListener('dragstart', function(e) {
draggedBlock = this;
this.classList.add('dragging');
e.dataTransfer.setData('text/plain', this.outerHTML);
});
block.addEventListener('dragend', function() {
this.classList.remove('dragging');
draggedBlock = null;
});
}
// Setup block click functionality
function setupBlockClick(block) {
block.addEventListener('click', function(e) {
// Don't activate if we're clicking on options
if (e.target.closest('.block-options') || e.target.classList.contains('fa-chevron-down')) {
return;
}
// Deactivate previous active block
if (activeBlock) {
activeBlock.classList.remove('active');
}
// Activate this block
this.classList.add('active');
activeBlock = this;
// Execute the block's action
const blockType = this.getAttribute('data-block');
executeBlock(blockType, this);
});
}
// Setup block connectors
function setupBlockConnectors(block) {
// Setup bottom connector
const connector = block.querySelector('.block-connector');
if (connector) {
connector.addEventListener('dragover', function(e) {
e.preventDefault();
this.style.backgroundColor = 'rgba(110, 69, 226, 0.4)';
});
connector.addEventListener('dragleave', function() {
this.style.backgroundColor = 'rgba(110, 69, 226, 0.2)';
});
connector.addEventListener('drop', function(e) {
e.preventDefault();
this.style.backgroundColor = 'rgba(110, 69, 226, 0.2)';
if (draggedBlock) {
// Generate unique ID for the block
const blockId = 'block-' + Date.now() + '-' + Math.floor(Math.random() * 1000);
const newBlock = draggedBlock.cloneNode(true);
newBlock.id = blockId;
newBlock.classList.add('connected-block');
newBlock.style.position = 'relative';
newBlock.style.left = '0';
newBlock.style.top = '0';
newBlock.style.margin = '0';
// Check if this block already exists in workspace
if (!blockInstances.has(blockId)) {
// Insert after the current block
block.parentNode.insertBefore(newBlock, block.nextSibling);
blockInstances.add(blockId);
// Setup drag for the new block
setupBlockDrag(newBlock);
// Setup connectors for the new block
setupBlockConnectors(newBlock);
// Setup click for the new block
setupBlockClick(newBlock);
}
}
});
}
// Setup block slots (for if, repeat, etc.)
const slots = block.querySelectorAll('.block-slot');
slots.forEach(slot => {
slot.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('highlight');
});
slot.addEventListener('dragleave', function() {
this.classList.remove('highlight');
});
slot.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('highlight');
if (draggedBlock) {
// Generate unique ID for the block
const blockId = 'block-' + Date.now() + '-' + Math.floor(Math.random() * 1000);
const newBlock = draggedBlock.cloneNode(true);
newBlock.id = blockId;
newBlock.style.position = 'relative';
newBlock.style.left = '0';
newBlock.style.top = '0';
newBlock.style.margin = '5px 0';
// Check if this block already exists in workspace
if (!blockInstances.has(blockId)) {
// Clear the slot and add the new block
this.innerHTML = '';
this.appendChild(newBlock);
blockInstances.add(blockId);
// Setup drag for the new block
setupBlockDrag(newBlock);
// Setup connectors for the new block
setupBlockConnectors(newBlock);
// Setup click for the new block
setupBlockClick(newBlock);
}
}
});
});
}
// Make elements draggable
function makeDraggable(element) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
element.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// Get the mouse cursor position at startup
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// Calculate the new cursor position
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// Set the element's new position
element.style.top = (element.offsetTop - pos2) + "px";
element.style.left = (element.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// Stop moving when mouse button is released
document.onmouseup = null;
document.onmousemove = null;
}
}
// Tab functionality
function changeTab(tabName) {
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('active');
btn.classList.remove('border-b-2');
btn.classList.remove('border-purple-600');
});
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
event.target.classList.add('active');
event.target.classList.add('border-b-2');
event.target.classList.add('border-purple-600');
document.getElementById(tabName).classList.add('active');
}
function changeRightTab(tabName) {
document.querySelectorAll('#properties, #multiplayer, #developers').forEach(tab => {
tab.classList.remove('active');
});
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('active');
btn.classList.remove('border-b-2');
btn.classList.remove('border-purple-600');
});
event.target.classList.add('active');
event.target.classList.add('border-b-2');
event.target.classList.add('border-purple-600');
document.getElementById(tabName).classList.add('active');
}
// Script execution functions
function runScripts() {
if (isRunning) {
stopScripts();
}
isRunning = true;
activeScripts = [];
// Find all "when flag clicked" blocks in workspace
const flagBlocks = document.querySelectorAll('#workspace [data-block="whenFlag"]');
flagBlocks.forEach(block => {
const script = [];
let currentBlock = block;
// Collect all connected blocks below the flag block
while (currentBlock) {
script.push(currentBlock);
// Check if there's a block connected below
const nextBlock = currentBlock.nextElementSibling;
if (nextBlock && nextBlock.classList.contains('connected-block')) {
currentBlock = nextBlock;
} else {
currentBlock = null;
}
}
if (script.length > 0) {
activeScripts.push(script);
}
});
// Execute all collected scripts
activeScripts.forEach(script => {
executeScript(script);
});
}
function stopScripts() {
isRunning = false;
activeScripts = [];
// Reset sprite position to center
const sprite = document.getElementById('currentSprite');
sprite.style.left = '50%';
sprite.style.top = '50%';
sprite.style.transform = 'translate(-50%, -50%)';
// Remove active state from all blocks
document.querySelectorAll('.block.active').forEach(block => {
block.classList.remove('active');
});
activeBlock = null;
}
function executeScript(script) {
if (!isRunning) return;
let delay = 0;
script.forEach((block, index) => {
const blockType = block.getAttribute('data-block');
setTimeout(() => {
if (!isRunning) return;
// Highlight the current executing block
block.classList.add('active');
setTimeout(() => {
block.classList.remove('active');
}, 500);
// Execute the block's action
executeBlock(blockType, block);
}, delay);
// Add delay between blocks (1 second by default)
delay += 1000;
});
}
function executeBlock(blockType, blockElement) {
const sprite = document.getElementById('currentSprite');
let value = '';
// Get the selected value from the block if it has options
if (blockElement) {
const blockText = blockElement.querySelector('span').textContent;
switch(blockType) {
case 'whenFlag':
value = blockText.match(/when flag clicked \((.*)\)/)?.[1] || 'all';
// In a full implementation, this would filter which blocks to execute
break;
case 'whenKey':
value = blockText.match(/when (.*) pressed/)[1];
break;
case 'move':
const moveMatch = blockText.match(/move (.*) steps( back)?/);
value = moveMatch[2] ? '-' + moveMatch[1] : moveMatch[1];
break;
case 'turn':
const turnMatch = blockText.match(/turn (.*) degrees( left)?/);
value = turnMatch[2] ? '-' + turnMatch[1] : turnMatch[1];
break;
case 'goTo':
value = blockText.match(/go to (.*)/)[1];
break;
case 'say':
value = blockText.match(/say (.*) for/)[1];
break;
case 'changeSize':
value = blockText.match(/change size by (.*)/)[1];
break;
case 'playSound':
value = blockText.match(/play sound (.*)/)[1];
break;
case 'wait':
value = blockText.match(/wait (.*) second/)[1];
break;
case 'repeat':
value = blockText.match(/repeat (.*) times/)[1];
break;
}
}
switch(blockType) {
case 'whenFlag':
// This is just a trigger, no action needed
break;
case 'afterThis':
// This is just a connector, no action needed
break;
case 'move':
const currentLeft = parseInt(sprite.style.left || '50%');
sprite.style.left = (currentLeft + parseInt(value)) + 'px';
break;
case 'turn':
const currentRotation = parseInt(sprite.style.transform.replace(/[^0-9\-]/g, '') || '0');
sprite.style.transform = `translate(-50%, -50%) rotate(${currentRotation + parseInt(value)}deg)`;
break;
case 'goTo':
const stage = document.getElementById('stage');
const stageRect = stage.getBoundingClientRect();
if (value === 'random') {
const randomX = Math.floor(Math.random() * (stageRect.width - 50));
const randomY = Math.floor(Math.random() * (stageRect.height - 50));
sprite.style.left = randomX + 'px';
sprite.style.top = randomY + 'px';
} else if (value === 'center') {
sprite.style.left = '50%';
sprite.style.top = '50%';
sprite.style.transform = 'translate(-50%, -50%)';
}
break;
case 'say':
// In a real implementation, this would show a speech bubble
alert(value);
break;
case 'changeCostume':
// Cycle through costumes
const currentIcon = sprite.querySelector('i');
if (currentIcon) {
if (currentIcon.classList.contains('fa-cat')) {
currentIcon.className = 'fas fa-dog text-4xl text-blue-600';
} else if (currentIcon.classList.contains('fa-dog')) {
currentIcon.className = 'fas fa-user text-4xl text-yellow-600';
} else {
currentIcon.className = 'fas fa-cat text-4xl text-purple-600';
}
}
break;
case 'changeSize':
const currentSize = parseInt(sprite.style.fontSize || '40');
sprite.style.fontSize = (currentSize + parseInt(value)) + 'px';
break;
case 'playSound':
// In a real implementation, this would play the actual sound
console.log('Playing sound:', value);
alert(`Playing ${value} sound`);
break;
case 'stopSound':
// In a real implementation, this would stop all sounds
console.log('Stopping all sounds');
break;
case 'wait':
// The delay is already handled by the script execution
break;
case 'repeat':
// In a full implementation, this would repeat the nested blocks
break;
case 'whenKey':
// This is just a trigger, no action needed
break;
case 'if':
// In a full implementation, this would check condition and execute nested blocks
break;
}
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=DeepSiteOptional/turboned-developent" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>