PHP Code Editor
<?php /** * RUBIK SOLVER PRO MAX - MONOLITHIC SCRIPT * Developer: Rizal */ // 1. LOGIKA BACKEND (PROSES DATA) if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER['HTTP_X_REQUESTED_WITH'])) { header('Content-Type: application/json'); // Simulasi Algoritma Lengkap Metode Pemula (LBL) // Format teks disesuaikan dengan permintaan user $fullSolution = [ "1. CROSS PUTIH: D' R' L2 U' F2", "2. CORNER LAYER 1: R U R' U' (4x)", "3. LAYER 2 (EDGES): U R U' R' F R' F' R", "4. CROSS KUNING: F R U R' U' F'", "5. ALIGN EDGES: R U R' U R U2 R'", "6. POSISI CORNER: U R U' L' U R' U' L", "7. ORIENTASI AKHIR: R' D' R D (Ulangi)" ]; echo json_encode([ 'status' => 'solved', 'moves' => implode("\n", $fullSolution) ]); exit; } ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>Rubik Solver Pro Max</title> <style> * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; user-select: none; } html, body { height: 100%; margin: 0; padding: 0; overflow: hidden; background: #0a0a0a; font-family: 'Segoe UI', Roboto, sans-serif; color: #fff; } body { display: flex; flex-direction: column; } /* Header UI */ #header { background: #1a1a1a; padding: 15px; border-bottom: 2px solid #333; text-align: center; z-index: 10; } .step-label { color: #3498db; font-weight: bold; font-size: 11px; letter-spacing: 2px; margin: 0; text-transform: uppercase; } .target-info { color: #fff; font-size: 16px; margin: 6px 0 0 0; display: flex; align-items: center; justify-content: center; font-weight: 600; } .color-dot { width: 18px; height: 18px; border-radius: 4px; border: 2px solid #fff; margin-left: 10px; box-shadow: 0 0 5px rgba(255,255,255,0.3); } /* Viewport Kamera */ .viewport { flex: 1; display: flex; align-items: center; justify-content: center; padding: 20px; background: radial-gradient(circle, #1a1a1a 0%, #0a0a0a 100%); } .rubik-frame { position: relative; width: 90vw; max-width: 350px; aspect-ratio: 1 / 1; border: 4px solid #f1c40f; border-radius: 24px; overflow: hidden; background: #000; box-shadow: 0 0 50px rgba(0,0,0,0.8); display: flex; align-items: center; justify-content: center; } video { position: absolute; width: 100%; height: 100%; object-fit: cover; background: #000; } .grid-container { position: relative; width: 85%; height: 85%; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr); pointer-events: none; z-index: 5; } .cell { border: 1.5px solid rgba(255, 255, 255, 0.4); display: flex; align-items: center; justify-content: center; } .aim-dot { width: 6px; height: 6px; background: #ff4757; border-radius: 50%; box-shadow: 0 0 10px #ff4757; } /* Panel Status & Solusi */ #display-panel { padding: 11px; text-align: center; background: #111; border-top: 1px solid #222; overflow-y: auto; max-height: 35vh; } #cam-status { font-family: 'Courier New', monospace; font-size: 13px; color: #2ecc71; margin-bottom: 10px; min-height: 1.2em; } .solusi-container { cursor: pointer; padding: 15px; border-radius: 12px; background: #1a1a1a; border: 1px solid #3498db; width: 100%; text-align: left; transition: all 0.2s; margin-top: 5px; } .solusi-container:active { transform: scale(0.98); background: #222; } .solusi-text { color: #f1c40f; font-size: 11px; font-weight: bold; line-height: 1.3; white-space: pre-wrap; font-family: 'Courier New', monospace; } .copy-hint { display: block; text-align: center; font-size: 10px; color: #777; margin-top: 8px; font-style: italic; } /* Footer Buttons */ .footer { background: #1a1a1a; padding: 16px; display: flex; gap: 13px; border-top: 1px solid #333; } button { flex: 1; padding: 16px 0; border: none; border-radius: 15px; font-weight: 800; font-size: 14px; cursor: pointer; color: #fff; text-transform: uppercase; transition: 0.3s; } #toggleBtn { background: #333; border: 1px solid #444; } #toggleBtn.on { background: #c0392b; border-color: #e74c3c; } #scanBtn { background: #2980b9; box-shadow: 0 4px 15px rgba(41, 128, 185, 0.3); } #scanBtn:disabled { background: #222; color: #555; border: 1px solid #333; box-shadow: none; cursor: not-allowed; } </style> </head> <body> <div id="header"> <p class="step-label" id="stepIdx">READY TO SCAN</p> <div class="target-info"> TENGAH: <span id="cName">-</span> <div id="cBox" class="color-dot" style="background:#333"></div> </div> </div> <div class="viewport"> <div class="rubik-frame"> <video id="v" autoplay playsinline></video> <div class="grid-container"> <?php for($i=0; $i<9; $i++) echo '<div class="cell"><div class="aim-dot"></div></div>'; ?> </div> </div> </div> <div id="display-panel"> <div id="cam-status">Sistem Siap. Klik 'BUKA KAMERA'.</div> <div id="solution-area"></div> </div> <div class="footer"> <button id="toggleBtn" onclick="handleCam()">BUKA KAMERA</button> <button id="scanBtn" onclick="snap()" disabled>AMBIL FOTO</button> </div> <textarea id="tempCopy" readonly style="position:fixed;top:-999px;opacity:0;"></textarea> <script> const v = document.getElementById('v'), statusTxt = document.getElementById('cam-status'), solArea = document.getElementById('solution-area'); const tBtn = document.getElementById('toggleBtn'), sBtn = document.getElementById('scanBtn'); const stepIdx = document.getElementById('stepIdx'), cName = document.getElementById('cName'), cBox = document.getElementById('cBox'); let stream = null, active = false, sides = []; const workflow = [ {n:"PUTIH",h:"white"},{n:"MERAH",h:"red"},{n:"HIJAU",h:"green"}, {n:"KUNING",h:"yellow"},{n:"ORANYE",h:"orange"},{n:"BIRU",h:"blue"} ]; async function handleCam() { if (!active) { // Bersihkan solusi lama saat memulai scan baru solArea.innerHTML = ""; sides = []; updateHeader(0); try { stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment", focusMode: "continuous" } }); v.srcObject = stream; active = true; tBtn.innerText = "MATIKAN"; tBtn.classList.add('on'); sBtn.disabled = false; statusTxt.innerText = "Fokuskan pada sisi " + workflow[0].n; } catch(e) { statusTxt.innerText = "Error: Kamera tidak diizinkan."; } } else { stopCamera(); } } function stopCamera() { if (stream) { stream.getTracks().forEach(track => track.stop()); v.srcObject = null; } active = false; tBtn.innerText = "BUKA KAMERA"; tBtn.classList.remove('on'); sBtn.disabled = true; statusTxt.innerText = "Kamera non-aktif."; } function updateHeader(index) { if (index < 6) { const info = workflow[index]; stepIdx.innerText = `LANGKAH ${index + 1} DARI 6`; cName.innerText = info.n; cBox.style.background = info.h; } } function snap() { if(sides.length < 6) { sides.push("SISI_" + workflow[sides.length].n); if (navigator.vibrate) navigator.vibrate(40); if (sides.length < 6) { updateHeader(sides.length); statusTxt.innerText = `Sisi ${workflow[sides.length-1].n} OK. Lanjut ke ${workflow[sides.length].n}.`; } else { processSolve(); } } } function processSolve() { sBtn.disabled = true; statusTxt.innerText = "MENGANALISIS POLA..."; const fd = new FormData(); fd.append('cube_data', JSON.stringify(sides)); fetch('', { method: 'POST', body: fd, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(r => r.json()) .then(data => { statusTxt.innerText = "SOLUSI DITEMUKAN!"; renderSolutionUI(data.moves); stepIdx.innerText = "SELESAI"; stopCamera(); // Solusi tetap ada di area display meski kamera mati }) .catch(err => { statusTxt.innerText = "Gagal memproses data."; sBtn.disabled = false; }); } function renderSolutionUI(moves) { solArea.innerHTML = ` <div id="solusiBox" class="solusi-container" onclick="copyToClipboard(\`${moves}\`)"> <div class="solusi-text">${moves}</div> </div> `; solArea.scrollIntoView({ behavior: 'smooth' }); } function copyToClipboard(text) { const textArea = document.getElementById("tempCopy"); textArea.value = text; textArea.select(); document.execCommand("copy"); const box = document.getElementById('solusiBox'); const oldContent = box.innerHTML; box.style.borderColor = "#2ecc71"; box.innerHTML = `<div style="text-align:center; color:#2ecc71; font-weight:bold; padding:20px;">✓ BERHASIL DISALIN</div>`; setTimeout(() => { box.style.borderColor = "#3498db"; box.innerHTML = oldContent; }, 1500); } </script> </body> </html>
Run Code
<?php /** * RUBIK SOLVER PRO MAX - MONOLITHIC SCRIPT * Developer: Rizal */ // 1. LOGIKA BACKEND (PROSES DATA) if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER['HTTP_X_REQUESTED_WITH'])) { header('Content-Type: application/json'); // Simulasi Algoritma Lengkap Metode Pemula (LBL) // Format teks disesuaikan dengan permintaan user $fullSolution = [ "1. CROSS PUTIH: D' R' L2 U' F2", "2. CORNER LAYER 1: R U R' U' (4x)", "3. LAYER 2 (EDGES): U R U' R' F R' F' R", "4. CROSS KUNING: F R U R' U' F'", "5. ALIGN EDGES: R U R' U R U2 R'", "6. POSISI CORNER: U R U' L' U R' U' L", "7. ORIENTASI AKHIR: R' D' R D (Ulangi)" ]; echo json_encode([ 'status' => 'solved', 'moves' => implode("\n", $fullSolution) ]); exit; } ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>Rubik Solver Pro Max</title> <style> * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; user-select: none; } html, body { height: 100%; margin: 0; padding: 0; overflow: hidden; background: #0a0a0a; font-family: 'Segoe UI', Roboto, sans-serif; color: #fff; } body { display: flex; flex-direction: column; } /* Header UI */ #header { background: #1a1a1a; padding: 15px; border-bottom: 2px solid #333; text-align: center; z-index: 10; } .step-label { color: #3498db; font-weight: bold; font-size: 11px; letter-spacing: 2px; margin: 0; text-transform: uppercase; } .target-info { color: #fff; font-size: 16px; margin: 6px 0 0 0; display: flex; align-items: center; justify-content: center; font-weight: 600; } .color-dot { width: 18px; height: 18px; border-radius: 4px; border: 2px solid #fff; margin-left: 10px; box-shadow: 0 0 5px rgba(255,255,255,0.3); } /* Viewport Kamera */ .viewport { flex: 1; display: flex; align-items: center; justify-content: center; padding: 20px; background: radial-gradient(circle, #1a1a1a 0%, #0a0a0a 100%); } .rubik-frame { position: relative; width: 90vw; max-width: 350px; aspect-ratio: 1 / 1; border: 4px solid #f1c40f; border-radius: 24px; overflow: hidden; background: #000; box-shadow: 0 0 50px rgba(0,0,0,0.8); display: flex; align-items: center; justify-content: center; } video { position: absolute; width: 100%; height: 100%; object-fit: cover; background: #000; } .grid-container { position: relative; width: 85%; height: 85%; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr); pointer-events: none; z-index: 5; } .cell { border: 1.5px solid rgba(255, 255, 255, 0.4); display: flex; align-items: center; justify-content: center; } .aim-dot { width: 6px; height: 6px; background: #ff4757; border-radius: 50%; box-shadow: 0 0 10px #ff4757; } /* Panel Status & Solusi */ #display-panel { padding: 11px; text-align: center; background: #111; border-top: 1px solid #222; overflow-y: auto; max-height: 35vh; } #cam-status { font-family: 'Courier New', monospace; font-size: 13px; color: #2ecc71; margin-bottom: 10px; min-height: 1.2em; } .solusi-container { cursor: pointer; padding: 15px; border-radius: 12px; background: #1a1a1a; border: 1px solid #3498db; width: 100%; text-align: left; transition: all 0.2s; margin-top: 5px; } .solusi-container:active { transform: scale(0.98); background: #222; } .solusi-text { color: #f1c40f; font-size: 11px; font-weight: bold; line-height: 1.3; white-space: pre-wrap; font-family: 'Courier New', monospace; } .copy-hint { display: block; text-align: center; font-size: 10px; color: #777; margin-top: 8px; font-style: italic; } /* Footer Buttons */ .footer { background: #1a1a1a; padding: 16px; display: flex; gap: 13px; border-top: 1px solid #333; } button { flex: 1; padding: 16px 0; border: none; border-radius: 15px; font-weight: 800; font-size: 14px; cursor: pointer; color: #fff; text-transform: uppercase; transition: 0.3s; } #toggleBtn { background: #333; border: 1px solid #444; } #toggleBtn.on { background: #c0392b; border-color: #e74c3c; } #scanBtn { background: #2980b9; box-shadow: 0 4px 15px rgba(41, 128, 185, 0.3); } #scanBtn:disabled { background: #222; color: #555; border: 1px solid #333; box-shadow: none; cursor: not-allowed; } </style> </head> <body> <div id="header"> <p class="step-label" id="stepIdx">READY TO SCAN</p> <div class="target-info"> TENGAH: <span id="cName">-</span> <div id="cBox" class="color-dot" style="background:#333"></div> </div> </div> <div class="viewport"> <div class="rubik-frame"> <video id="v" autoplay playsinline></video> <div class="grid-container"> <?php for($i=0; $i<9; $i++) echo '<div class="cell"><div class="aim-dot"></div></div>'; ?> </div> </div> </div> <div id="display-panel"> <div id="cam-status">Sistem Siap. Klik 'BUKA KAMERA'.</div> <div id="solution-area"></div> </div> <div class="footer"> <button id="toggleBtn" onclick="handleCam()">BUKA KAMERA</button> <button id="scanBtn" onclick="snap()" disabled>AMBIL FOTO</button> </div> <textarea id="tempCopy" readonly style="position:fixed;top:-999px;opacity:0;"></textarea> <script> const v = document.getElementById('v'), statusTxt = document.getElementById('cam-status'), solArea = document.getElementById('solution-area'); const tBtn = document.getElementById('toggleBtn'), sBtn = document.getElementById('scanBtn'); const stepIdx = document.getElementById('stepIdx'), cName = document.getElementById('cName'), cBox = document.getElementById('cBox'); let stream = null, active = false, sides = []; const workflow = [ {n:"PUTIH",h:"white"},{n:"MERAH",h:"red"},{n:"HIJAU",h:"green"}, {n:"KUNING",h:"yellow"},{n:"ORANYE",h:"orange"},{n:"BIRU",h:"blue"} ]; async function handleCam() { if (!active) { // Bersihkan solusi lama saat memulai scan baru solArea.innerHTML = ""; sides = []; updateHeader(0); try { stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment", focusMode: "continuous" } }); v.srcObject = stream; active = true; tBtn.innerText = "MATIKAN"; tBtn.classList.add('on'); sBtn.disabled = false; statusTxt.innerText = "Fokuskan pada sisi " + workflow[0].n; } catch(e) { statusTxt.innerText = "Error: Kamera tidak diizinkan."; } } else { stopCamera(); } } function stopCamera() { if (stream) { stream.getTracks().forEach(track => track.stop()); v.srcObject = null; } active = false; tBtn.innerText = "BUKA KAMERA"; tBtn.classList.remove('on'); sBtn.disabled = true; statusTxt.innerText = "Kamera non-aktif."; } function updateHeader(index) { if (index < 6) { const info = workflow[index]; stepIdx.innerText = `LANGKAH ${index + 1} DARI 6`; cName.innerText = info.n; cBox.style.background = info.h; } } function snap() { if(sides.length < 6) { sides.push("SISI_" + workflow[sides.length].n); if (navigator.vibrate) navigator.vibrate(40); if (sides.length < 6) { updateHeader(sides.length); statusTxt.innerText = `Sisi ${workflow[sides.length-1].n} OK. Lanjut ke ${workflow[sides.length].n}.`; } else { processSolve(); } } } function processSolve() { sBtn.disabled = true; statusTxt.innerText = "MENGANALISIS POLA..."; const fd = new FormData(); fd.append('cube_data', JSON.stringify(sides)); fetch('', { method: 'POST', body: fd, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(r => r.json()) .then(data => { statusTxt.innerText = "SOLUSI DITEMUKAN!"; renderSolutionUI(data.moves); stepIdx.innerText = "SELESAI"; stopCamera(); // Solusi tetap ada di area display meski kamera mati }) .catch(err => { statusTxt.innerText = "Gagal memproses data."; sBtn.disabled = false; }); } function renderSolutionUI(moves) { solArea.innerHTML = ` <div id="solusiBox" class="solusi-container" onclick="copyToClipboard(\`${moves}\`)"> <div class="solusi-text">${moves}</div> </div> `; solArea.scrollIntoView({ behavior: 'smooth' }); } function copyToClipboard(text) { const textArea = document.getElementById("tempCopy"); textArea.value = text; textArea.select(); document.execCommand("copy"); const box = document.getElementById('solusiBox'); const oldContent = box.innerHTML; box.style.borderColor = "#2ecc71"; box.innerHTML = `<div style="text-align:center; color:#2ecc71; font-weight:bold; padding:20px;">✓ BERHASIL DISALIN</div>`; setTimeout(() => { box.style.borderColor = "#3498db"; box.innerHTML = oldContent; }, 1500); } </script> </body> </html>
Run Code New Tab
Result