mrbananaguy1234

OpenBlox open-source client code

May 16th, 2026 (edited)
51
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.64 KB | Gaming | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>OpenBlox</title>
  7. <link rel="stylesheet" href="./style.css">
  8.  
  9. </head>
  10.  
  11. <body>
  12. <!-- Rendering parent -->
  13. <div id="canvas"></div>
  14. <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js'></script>
  15. <script src='https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js'></script>
  16. <script src='https://cdn.jsdelivr.net/npm/[email protected]/ejs.min.js'></script>
  17. <script src='https://[email protected]/examples/js/controls/OrbitControls.js'></script><script src="./script.js"></script>
  18.  
  19. <script>
  20. ///////////////////////////////////////
  21. // 1. Initialization & Variables //////
  22. let targetX = 0, targetY = 0, zoom = 8;
  23. let activeShapeType = 'box', activeColorHex = 0xff0000;
  24. const shapesList = ['box', 'sphere', 'cylinder'];
  25. const colorsList = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00];
  26.  
  27. const keys = { w: false, a: false, s: false, d: false, space: false };
  28. window.addEventListener('keydown', e => {
  29. if (e.key === ' ') keys.space = true;
  30. else if (e.key.toLowerCase() === 'q') toggleNextShape();
  31. else if (e.key.toLowerCase() === 'e') toggleNextColor();
  32. else keys[e.key.toLowerCase()] = true;
  33. });
  34. window.addEventListener('keyup', e => { if (e.key === ' ') keys.space = false; else keys[e.key.toLowerCase()] = false; });
  35.  
  36. // --- CUSTOM ROBLOX CURSOR ---
  37. const fakeCursor = document.createElement('div');
  38. fakeCursor.style.cssText = 'position:fixed; width:18px; height:18px; background:white; border:2px solid black; pointer-events:none; z-index:99999;';
  39. document.body.appendChild(fakeCursor);
  40.  
  41. const cursorStyle = document.createElement('style');
  42. cursorStyle.innerHTML = 'body, #canvas { cursor: none !important; }';
  43. document.head.appendChild(cursorStyle);
  44.  
  45. let isRightClicking = false;
  46. window.addEventListener('mousedown', e => { if (e.button === 2) isRightClicking = true; });
  47. window.addEventListener('mouseup', e => { if (e.button === 2) isRightClicking = false; });
  48.  
  49. window.addEventListener('mousemove', e => {
  50. if (!isRightClicking) { fakeCursor.style.left = e.clientX + 'px'; fakeCursor.style.top = e.clientY + 'px'; }
  51. else { targetX += e.movementX * 0.005; targetY += e.movementY * 0.005; if (targetY < -1.4) targetY = -1.4; if (targetY > 1.4) targetY = 1.4; }
  52. });
  53.  
  54. window.addEventListener('wheel', e => { zoom += e.deltaY * 0.02; if (zoom < 3) zoom = 3; if (zoom > 40) zoom = 40; });
  55. window.addEventListener('contextmenu', e => e.preventDefault());
  56.  
  57. var world = new CANNON.World(); world.gravity.set(0, -18, 0); var fixedTimeStep = 1.0 / 60.0;
  58. const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  59. const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0xffffff);
  60. document.getElementById("canvas").appendChild(renderer.domElement);
  61.  
  62. const raycaster = new THREE.Raycaster(), mouseVector = new THREE.Vector2();
  63. let previewGuideMesh;
  64.  
  65. ///////////////////////////////////////
  66. // CENTRALIZED ENTITY SPANNER SYSTEM //
  67. ///////////////////////////////////////
  68. const gameEntities = {}, buildableTargetsArray = [];
  69. let entityIdCounter = 0, playerIdCounter = 0;
  70.  
  71. function spawnEntity(type = 'box', config = {}) {
  72. const id = "ent_" + (entityIdCounter++);
  73. const x = config.x || 0, y = config.y || 10, z = config.z || 0, color = config.color || 0xff0000;
  74. const hasPhysics = config.hasPhysics !== undefined ? config.hasPhysics : true;
  75. let geometry, shape, w = config.w || 2, h = config.h || 2, d = config.d || 2, radius = config.radius || 1;
  76.  
  77. if (type === 'sphere') { geometry = new THREE.SphereGeometry(radius, 24, 24); shape = new CANNON.Sphere(radius); }
  78. else if (type === 'cylinder') { geometry = new THREE.CylinderGeometry(1, 1, h, 16); shape = new CANNON.Cylinder(1, 1, h, 16); }
  79. else { geometry = new THREE.BoxGeometry(w, h, d); shape = new CANNON.Box(new CANNON.Vec3(w / 2, h / 2, d / 2)); }
  80.  
  81. const material = new THREE.MeshStandardMaterial({ color: color, emissive: color, emissiveIntensity: 0.15, roughness: 0.6 });
  82. const mesh = new THREE.Mesh(geometry, material); mesh.position.set(x, y, z); scene.add(mesh);
  83.  
  84. let body = null;
  85. if (hasPhysics) { body = new CANNON.Body({ mass: config.mass || 0, position: new CANNON.Vec3(x, y, z), shape: shape }); world.addBody(body); }
  86. gameEntities[id] = { id, type, mesh, body, material, size: { w, h, d, radius }, hasPhysics };
  87. buildableTargetsArray.push(mesh);
  88. return id;
  89. }
  90.  
  91. function spawnPlayerInstance(x, y, z, customColors = {}) {
  92. const pId = "player_clone_" + (playerIdCounter++); const cloneGroup = new THREE.Group();
  93. const yellowMat = new THREE.MeshStandardMaterial({ color: 0xffd800, emissive: 0xffd800, emissiveIntensity: 0.25, roughness: 0.6 });
  94. const blueMat = new THREE.MeshStandardMaterial({ color: customColors.torsoColor || 0x0054a6, emissive: customColors.torsoColor || 0x0054a6, emissiveIntensity: 0.25, roughness: 0.6 });
  95. const greenMat = new THREE.MeshStandardMaterial({ color: 0x4cb13c, emissive: 0x4cb13c, emissiveIntensity: 0.25, roughness: 0.6 });
  96.  
  97. const leftLeg = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), greenMat); leftLeg.position.set(-0.5, 1.0, 0); cloneGroup.add(leftLeg);
  98. const rightLeg = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), greenMat); rightLeg.position.set(0.5, 1.0, 0); cloneGroup.add(rightLeg);
  99. const torso = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 1), blueMat); torso.position.y = 3.0; cloneGroup.add(torso);
  100. const head = new THREE.Mesh(new THREE.BoxGeometry(1.2, 1.2, 1.2), yellowMat); head.position.y = 4.6; cloneGroup.add(head);
  101. const leftArm = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), yellowMat); leftArm.position.set(-1.5, 3.0, 0); cloneGroup.add(leftArm);
  102. const rightArm = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), yellowMat); rightArm.position.set(1.5, 3.0, 0); cloneGroup.add(rightArm);
  103.  
  104. cloneGroup.scale.set(0.75, 0.75, 0.75); cloneGroup.position.set(x, y, z); scene.add(cloneGroup);
  105. return pId;
  106. }
  107.  
  108. ///////////////////////////////////////
  109. // 2. Objects & Lights ////////////////
  110. let ground, player, sphereBody, groundBody;
  111. let playerRotationY = 0, targetRotationY = 0, playerVelocityY = 0, isGrounded = true;
  112.  
  113. function setupScene() {
  114. ground = new THREE.Mesh(new THREE.BoxGeometry(40, 1, 40), new THREE.MeshPhysicalMaterial({ color: 0x00ff00 })); ground.name = "ground"; scene.add(ground);
  115. scene.add(new THREE.AmbientLight(0x404040, 0.5)); const dLight = new THREE.DirectionalLight(0xffffff, 0.8); dLight.position.set(5, 10, 7); scene.add(dLight);
  116.  
  117. player = new THREE.Group();
  118. const yellowMat = new THREE.MeshStandardMaterial({ color: 0xffd800, emissive: 0xffd800, emissiveIntensity: 0.25, roughness: 0.6 });
  119. const blueMat = new THREE.MeshStandardMaterial({ color: 0x0054a6, emissive: 0x0054a6, emissiveIntensity: 0.25, roughness: 0.6 });
  120. const greenMat = new THREE.MeshStandardMaterial({ color: 0x4cb13c, emissive: 0x4cb13c, emissiveIntensity: 0.25, roughness: 0.6 });
  121.  
  122. const leftLeg = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), greenMat); leftLeg.position.set(-0.5, 1.0, 0); player.add(leftLeg);
  123. const rightLeg = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), greenMat); rightLeg.position.set(0.5, 1.0, 0); player.add(rightLeg);
  124. const torso = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 1), blueMat); torso.position.y = 3.0; player.add(torso);
  125. const head = new THREE.Mesh(new THREE.BoxGeometry(1.2, 1.2, 1.2), yellowMat); head.position.y = 4.6; player.add(head);
  126. const leftArm = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), yellowMat); leftArm.position.set(-1.5, 3.0, 0); player.add(leftArm);
  127. const rightArm = new THREE.Mesh(new THREE.BoxGeometry(1, 2, 1), yellowMat); rightArm.position.set(1.5, 3.0, 0); player.add(rightArm);
  128. player.scale.set(0.75, 0.75, 0.75); player.position.set(3, 0.5, 0); scene.add(player);
  129.  
  130. groundBody = new CANNON.Body({ mass: 0, shape: new CANNON.Box(new CANNON.Vec3(20, 0.5, 20)) }); world.addBody(groundBody);
  131. window.mainPhysicsBallId = spawnEntity('sphere', { x: 0, y: 15, z: 0, color: 0x00a2ff, radius: 1, mass: 5 }); sphereBody = gameEntities[window.mainPhysicsBallId].body;
  132.  
  133. updatePreviewGuideGeometry();
  134. }
  135.  
  136. function checkPlayerBlockCollisions(nextX, nextZ) {
  137. const pRadius = 0.8;
  138. for (let id in gameEntities) {
  139. const ent = gameEntities[id]; if (!ent.hasPhysics || ent.type !== 'box') continue;
  140. const collisionX = nextX + pRadius > ent.mesh.position.x - (ent.size.w/2) && nextX - pRadius < ent.mesh.position.x + (ent.size.w/2);
  141. const collisionZ = nextZ + pRadius > ent.mesh.position.z - (ent.size.d/2) && nextZ - pRadius < ent.mesh.position.z + (ent.size.d/2);
  142. const collisionY = player.position.y < (ent.mesh.position.y + ent.size.h/2) - 0.1 && player.position.y + 3 > ent.mesh.position.y - ent.size.h/2;
  143. if (collisionX && collisionZ && collisionY) return true;
  144. }
  145. return false;
  146. }
  147.  
  148. window.addEventListener('keydown', e => { if (e.key.toLowerCase() === 'p') spawnPlayerInstance(player.position.x, player.position.y, player.position.z, { torsoColor: 0xff0000 }); });
  149.  
  150. // --- LEFT CLICK PLACE ---
  151. window.addEventListener('mousedown', e => {
  152. if (e.clientY < 80) return;
  153. if (e.button === 0) {
  154. mouseVector.x = (e.clientX / window.innerWidth) * 2 - 1; mouseVector.y = -(e.clientY / window.innerHeight) * 2 + 1;
  155. raycaster.setFromCamera(mouseVector, camera);
  156. const intersections = raycaster.intersectObjects([ground, ...buildableTargetsArray]);
  157. if (intersections.length > 0) {
  158. const hit = intersections[0]; let sX, sY, sZ;
  159. if (hit.object.name === "ground") { sX = Math.round(hit.point.x / 2) * 2; sZ = Math.round(hit.point.z / 2) * 2; sY = activeShapeType === 'sphere' ? 1 : 1.5; }
  160. else {
  161. const normal = hit.face.normal.clone().transformDirection(hit.object.matrixWorld);
  162. sX = Math.round((hit.object.position.x + normal.x * 2) / 2) * 2; sY = Math.round((hit.object.position.y + normal.y * 2) / 2) * 2; sZ = Math.round((hit.object.position.z + normal.z * 2) / 2) * 2;
  163. }
  164. spawnEntity(activeShapeType, { x: sX, y: sY, z: sZ, color: activeColorHex, mass: 0 });
  165. }
  166. }
  167. });
  168.  
  169. function updatePreviewGuideGeometry() {
  170. if (previewGuideMesh) scene.remove(previewGuideMesh);
  171. let geo = activeShapeType === 'sphere' ? new THREE.SphereGeometry(1.02, 16, 16) : (activeShapeType === 'cylinder' ? new THREE.CylinderGeometry(1.02, 1.02, 2.02, 12) : new THREE.BoxGeometry(2.02, 2.02, 2.02));
  172. previewGuideMesh = new THREE.Mesh(geo, new THREE.MeshBasicMaterial({ color: activeColorHex, wireframe: true, transparent: true, opacity: 0.6 }));
  173. scene.add(previewGuideMesh);
  174. }
  175. function toggleNextShape() { activeShapeType = shapesList[(shapesList.indexOf(activeShapeType) + 1) % shapesList.length]; updatePreviewGuideGeometry(); document.getElementById('hud-shape-txt').innerText = activeShapeType.toUpperCase(); }
  176. function toggleNextColor() { activeColorHex = colorsList[(colorsList.indexOf(activeColorHex) + 1) % colorsList.length]; updatePreviewGuideGeometry(); document.getElementById('hud-color-dot').style.background = '#' + activeColorHex.toString(16).padStart(6, '0'); }
  177.  
  178. setupScene();
  179.  
  180. // --- PURE JAVASCRIPT HUD ---
  181. (function injectHUD() {
  182. const hud = document.createElement('div'); hud.style.cssText = 'position:absolute; top:20px; left:50%; transform:translateX(-50%); background:rgba(20,20,20,0.85); padding:10px 20px; border-radius:6px; border-bottom:4px solid #FF0000; display:flex; align-items:center; gap:20px; z-index:100; color:white; font-family:Arial; font-size:12px; box-shadow:0 4px 15px rgba(0,0,0,0.5);';
  183. hud.innerHTML = '<div><strong>SHAPE [Q]:</strong> <span id="hud-shape-txt" style="color:#FF0000; font-weight:bold;">BOX</span></div><div style="display:flex;align-items:center;gap:6px;"><strong>COLOR [E]:</strong> <div id="hud-color-dot" style="width:14px;height:14px;border-radius:50%;background:#FF0000;border:1px solid white;"></div></div>';
  184.  
  185. const btn = document.createElement('button'); btn.innerText = '💾 EXPORT JSON'; btn.style.cssText = 'background:#FF0000; color:white; border:none; padding:6px 12px; font-weight:bold; border-radius:4px; cursor:pointer;';
  186. btn.onclick = () => {
  187. const data = []; for (let id in gameEntities) { const ent = gameEntities[id]; data.push({ type: ent.type, x: ent.mesh.position.x, y: ent.mesh.position.y, z: ent.mesh.position.z, color: ent.material.color.getHex() }); }
  188. navigator.clipboard.writeText(JSON.stringify(data)); alert("Map JSON string copied to clipboard! 📂");
  189. };
  190. hud.appendChild(btn); document.body.appendChild(hud);
  191. })();
  192.  
  193. ///////////////////////////////////////
  194. // 3. The Engine Loop /////////////////
  195. function animate() {
  196. requestAnimationFrame(animate); world.step(fixedTimeStep);
  197. for (let id in gameEntities) { const ent = gameEntities[id]; if (ent.body) { ent.mesh.position.copy(ent.body.position); ent.mesh.quaternion.copy(ent.body.quaternion); } }
  198.  
  199. // --- REAL-TIME WIREFRAME GUIDE ---
  200. mouseVector.x = (parseFloat(fakeCursor.style.left) / window.innerWidth) * 2 - 1; mouseVector.y = -(parseFloat(fakeCursor.style.top) / window.innerHeight) * 2 + 1;
  201. if (!isNaN(mouseVector.x) && !isNaN(mouseVector.y) && parseFloat(fakeCursor.style.top) > 80) {
  202. raycaster.setFromCamera(mouseVector, camera); const intersections = raycaster.intersectObjects([ground, ...buildableTargetsArray]);
  203. if (intersections.length > 0) {
  204. const hit = intersections[0]; previewGuideMesh.visible = true;
  205. if (hit.object.name === "ground") { previewGuideMesh.position.set(Math.round(hit.point.x/2)*2, activeShapeType==='cylinder'?1.5:(activeShapeType==='sphere'?1:1.5), Math.round(hit.point.z/2)*2); }
  206. else { const normal = hit.face.normal.clone().transformDirection(hit.object.matrixWorld); previewGuideMesh.position.set(Math.round((hit.object.position.x + normal.x * 2)/2)*2, Math.round((hit.object.position.y + normal.y * 2)/2)*2, Math.round((hit.object.position.z + normal.z * 2)/2)*2); }
  207. } else { previewGuideMesh.visible = false; }
  208. } else { if (previewGuideMesh) previewGuideMesh.visible = false; }
  209.  
  210. // --- WASD MOVEMENT ---
  211. const moveSpeed = 0.15; let moveX = 0, moveZ = 0;
  212. if (keys.w) { moveX -= Math.sin(targetX); moveZ -= Math.cos(targetX); } if (keys.s) { moveX += Math.sin(targetX); moveZ += Math.cos(targetX); }
  213. if (keys.a) { moveX -= Math.cos(targetX); moveZ += Math.sin(targetX); } if (keys.d) { moveX += Math.cos(targetX); moveZ -= Math.sin(targetX); }
  214. let moveLen = Math.sqrt(moveX * moveX + moveZ * moveZ);
  215. if (moveLen > 0) {
  216. let nextX = player.position.x + (moveX / moveLen) * moveSpeed, nextZ = player.position.z + (moveZ / moveLen) * moveSpeed;
  217. if (!checkPlayerBlockCollisions(nextX, nextZ)) { player.position.x = nextX; player.position.z = nextZ; }
  218. targetRotationY = Math.atan2(moveX, moveZ); playerRotationY += (Math.atan2(Math.sin(targetRotationY - playerRotationY), Math.cos(targetRotationY - playerRotationY))) * 0.15; player.rotation.y = playerRotationY;
  219. }
  220.  
  221. // --- GRAVITY & SURFACE DETECTOR ---
  222. let currentGroundLevel = 0.5;
  223. for (let id in gameEntities) {
  224. const ent = gameEntities[id]; if (!ent.hasPhysics || ent.type !== 'box') continue;
  225. const insideX = player.position.x + 0.5 > ent.mesh.position.x - ent.size.w/2 && player.position.x - 0.5 < ent.mesh.position.x + ent.size.w/2;
  226. const insideZ = player.position.z + 0.5 > ent.mesh.position.z - ent.size.d/2 && player.position.z - 0.5 < ent.mesh.position.z + ent.size.d/2;
  227. if (insideX && insideZ && player.position.y >= (ent.mesh.position.y + ent.size.h/2) - 0.2 && player.position.y <= (ent.mesh.position.y + ent.size.h/2) + 0.4) { currentGroundLevel = ent.mesh.position.y + ent.size.h/2; break; }
  228. }
  229. const isOnPlatform = player.position.x >= -20 && player.position.x <= 20 && player.position.z >= -20 && player.position.z <= 20;
  230. if (isOnPlatform && player.position.y <= currentGroundLevel && playerVelocityY <= 0) { player.position.y = currentGroundLevel; playerVelocityY = 0; isGrounded = true; } else { isGrounded = false; }
  231. if (keys.space && isGrounded) { playerVelocityY = 0.35; isGrounded = false; }
  232. if (!isGrounded) { playerVelocityY -= 0.018; player.position.y += playerVelocityY; }
  233.  
  234. if (player.position.y < -20) { player.position.set(0, 5.0, 0); playerVelocityY = 0; }
  235. if (sphereBody && sphereBody.position.y < -20) { sphereBody.position.set(0, 15, 0); sphereBody.velocity.set(0, 0, 0); sphereBody.angularVelocity.set(0, 0, 0); }
  236.  
  237. let dx = sphereBody.position.x - player.position.x, dz = sphereBody.position.z - player.position.z; let distance = Math.sqrt(dx * dx + dz * dz);
  238. if (distance < 1.5 && Math.abs(sphereBody.position.y - (player.position.y + 1.5)) < 2.0) { let pushForce = 14; sphereBody.velocity.x = (dx / distance) * pushForce; sphereBody.velocity.z = (dz / distance) * pushForce; }
  239.  
  240. camera.position.x = player.position.x + zoom * Math.sin(targetX) * Math.cos(targetY); camera.position.y = player.position.y + 1.5 + zoom * Math.sin(targetY); camera.position.z = player.position.z + zoom * Math.cos(targetX) * Math.cos(targetY);
  241. camera.lookAt(player.position.x, player.position.y + 1.5, player.position.z); renderer.render(scene, camera);
  242. }
  243. animate();
  244. window.addEventListener("resize", () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });
  245. </script>
  246. <style>
  247. body {
  248. margin: 0;
  249. overflow: hidden;
  250. }
  251. </style>
  252. </body>
  253.  
  254. </html>
  255.  
Advertisement
Comments
Add Comment
Please, Sign In to add comment