tutorial
Unblocked AI:https://gemini.google.com/app
DONT USE IT FOR CHEATS AT SCHOOL DO UR HOMEWORK YES IM TALKING TO U uhhh who am I talking toβ¦.
Drift V8
(function(){
if(window.driftEditorActive) return;
window.driftEditorActive = true;
console.log("ποΈ Drift Sandbox v10 β Area Paint, Ball Mode, Rotate & Explosives!");
// === Basic page setup ===
document.body.innerHTML = '';
document.body.style.margin = '0';
document.body.style.overflow = 'hidden';
document.body.style.background = 'white';
// === Canvas ===
const canvas = document.createElement('canvas');
canvas.width = innerWidth;
canvas.height = innerHeight;
canvas.style.position = 'fixed';
canvas.style.left = '150px';
canvas.style.top = '0';
canvas.style.zIndex = 10;
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d');
// === Sidebar UI ===
const sidebar = document.createElement('div');
sidebar.style.position = 'fixed';
sidebar.style.left = 0;
sidebar.style.top = 0;
sidebar.style.width = '150px';
sidebar.style.height = '100vh';
sidebar.style.background = '#f4f4f4';
sidebar.style.borderRight = '2px solid #ccc';
sidebar.style.display = 'flex';
sidebar.style.flexDirection = 'column';
sidebar.style.alignItems = 'center';
sidebar.style.paddingTop = '12px';
sidebar.style.fontFamily = 'sans-serif';
sidebar.style.zIndex = 20;
document.body.appendChild(sidebar);
function makeButton(label){
const b = document.createElement('button');
b.innerHTML = label;
b.style.margin = '6px';
b.style.padding = '6px 8px';
b.style.width = '120px';
b.style.cursor = 'pointer';
b.style.borderRadius = '8px';
b.style.border = '1px solid #888';
b.style.background = '#fff';
b.style.fontWeight = 'bold';
sidebar.appendChild(b);
return b;
}
// Tool buttons
const wallBtn = makeButton('π§± Wall');
const boostBtn = makeButton('β‘ Boost');
const mudBtn = makeButton('π€ Mud');
const iceBtn = makeButton('π§ Ice');
const slowBtn = makeButton('π’ Slower');
const boomBtn = makeButton('π₯ Explosive');
const stopBtn = makeButton('β Stopper');
const delBtn = makeButton('ποΈ Delete');
// Mode toggle (ball / area)
const modeBtn = makeButton('Mode: Ball');
let placementMode = 'ball'; // 'ball' or 'area'
// Help text
const help = document.createElement('div');
help.style.fontSize = '12px';
help.style.textAlign = 'center';
help.style.padding = '6px';
help.style.width = '130px';
help.innerHTML = 'Click tool β click to place.<br>Area mode: click corner A β click corner B.<br>Press <b>R</b> to rotate ghost.';
sidebar.appendChild(help);
// Nitro bar
const nitroBar = document.createElement('div');
nitroBar.style.position='fixed';
nitroBar.style.bottom='18px';
nitroBar.style.left='180px';
nitroBar.style.width='220px';
nitroBar.style.height='18px';
nitroBar.style.background='#ccc';
nitroBar.style.borderRadius='9px';
nitroBar.style.overflow='hidden';
nitroBar.style.border='2px solid #444';
nitroBar.style.zIndex = 30;
document.body.appendChild(nitroBar);
const nitroFill = document.createElement('div');
nitroFill.style.height='100%';
nitroFill.style.width='100%';
nitroFill.style.background='#00bfff';
nitroFill.style.transition='width 0.08s linear';
nitroBar.appendChild(nitroFill);
// === State ===
const placed = []; // placed objects {type,x,y,w?,h?,angle?}
let placingType = null;
let ghost = null; // {type,x,y,angle}
let areaStart = null; // for area mode first corner
let mouse = {x:0,y:0};
const explosions = []; // {x,y,radius,life,maxR}
const mudTrail = [];
// button handlers
function startPlacing(type){
placingType = type;
ghost = {type, x: mouse.x, y: mouse.y, angle: 0};
areaStart = null;
}
wallBtn.onclick = ()=> startPlacing('wall');
boostBtn.onclick = ()=> startPlacing('boost');
mudBtn.onclick = ()=> startPlacing('mud');
iceBtn.onclick = ()=> startPlacing('ice');
slowBtn.onclick = ()=> startPlacing('slow');
boomBtn.onclick = ()=> startPlacing('boom');
stopBtn.onclick = ()=> startPlacing('stop');
delBtn.onclick = ()=> { placingType = 'delete'; ghost = {type:'delete',x:mouse.x,y:mouse.y,angle:0}; areaStart=null; };
modeBtn.onclick = ()=>{
placementMode = placementMode === 'ball' ? 'area' : 'ball';
modeBtn.innerHTML = 'Mode: ' + (placementMode==='ball'? 'Ball' : 'Area');
areaStart = null;
};
// === Mouse events on canvas ===
canvas.addEventListener('mousemove', e=>{
mouse.x = e.clientX - 150;
mouse.y = e.clientY;
if(ghost) { ghost.x = mouse.x; ghost.y = mouse.y; }
});
canvas.addEventListener('click', e=>{
if(!placingType) return;
// delete mode single click: remove nearest
if(placingType === 'delete'){
const idx = placed.findIndex(o => Math.hypot(o.x - mouse.x, o.y - mouse.y) < (o.w||20) + 12);
if(idx !== -1) placed.splice(idx,1);
return;
}
if(placementMode === 'ball'){
// place a single object
placeObject(placingType, mouse.x, mouse.y, ghost && ghost.angle || 0);
if(placingType !== 'wall') { placingType = null; ghost = null; } // keep wall selected for convenience
return;
}
// area mode
if(!areaStart){
areaStart = {x: mouse.x, y: mouse.y, angle: ghost ? ghost.angle : 0};
} else {
// finalize rectangle from areaStart to current mouse
const x1 = Math.min(areaStart.x, mouse.x);
const y1 = Math.min(areaStart.y, mouse.y);
const x2 = Math.max(areaStart.x, mouse.x);
const y2 = Math.max(areaStart.y, mouse.y);
// fill grid with objects spaced by cell size
const cell = placementCellSizeFor(placingType);
const offsetX = cell/2;
const offsetY = cell/2;
for(let px = x1 + offsetX; px <= x2; px += cell){
for(let py = y1 + offsetY; py <= y2; py += cell){
placeObject(placingType, Math.round(px), Math.round(py), ghost ? ghost.angle : 0);
}
}
areaStart = null;
// keep placingType selected for repeat painting
}
});
// helper: choose a sensible cell size depending on type
function placementCellSizeFor(type){
switch(type){
case 'wall': return 44;
case 'boost': return 46;
case 'mud': return 52;
case 'ice': return 52;
case 'slow': return 46;
case 'boom': return 50;
case 'stop': return 44;
default: return 44;
}
}
// place single object helper
function placeObject(type, x, y, angle = 0){
// for walls we allow rotated rectangles (angle multiple of 90)
const obj = {type, x, y, angle: angle || 0};
// dimension presets (for collision checks & drawing)
if(type === 'wall'){
obj.w = 40; obj.h = 12;
// if angle is 90 or 270 swap w/h
const a = ((obj.angle % (Math.PI*2)) + Math.PI*2) % (Math.PI*2);
if(Math.abs(a - Math.PI/2) < 0.01 || Math.abs(a - 3*Math.PI/2) < 0.01){
[obj.w, obj.h] = [obj.h, obj.w];
}
} else if(type === 'boost'){ obj.r = 20; }
else if(type === 'mud'){ obj.r = 26; }
else if(type === 'ice'){ obj.r = 26; }
else if(type === 'slow'){ obj.r = 20; }
else if(type === 'boom'){ obj.r = 20; obj.explosive = true; obj.broken = false; }
else if(type === 'stop'){ obj.r = 18; }
placed.push(obj);
}
// rotate ghost with R
window.addEventListener('keydown', e=>{
if(e.key === 'r' || e.key === 'R'){
if(ghost){
// rotate by 90deg
ghost.angle = (ghost.angle || 0) + Math.PI/2;
// normalize
ghost.angle = ((ghost.angle % (Math.PI*2)) + Math.PI*2) % (Math.PI*2);
}
}
});
// === Car & physics ===
const car = {
x: canvas.width/2,
y: canvas.height/2,
angle: 0,
speed: 0,
accel: 0.22,
friction: 0.02,
turnFriction: 0.05,
turnRate: 0.07,
driftFactor: 0.86,
maxSpeed: 10.5,
boostTime: 0,
nitro: 100
};
const keys = {};
const trails = [];
window.addEventListener('keydown', e=>{
if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"," "].includes(e.key)) e.preventDefault();
keys[e.key] = true;
});
window.addEventListener('keyup', e=> keys[e.key] = false);
// place explosion when boom breaks
function spawnExplosion(x,y){
explosions.push({x,y,life:1,maxR:140,r:8});
}
// === Update car each frame ===
function updateCar(){
const isBoosting = car.boostTime > 0;
const isNitro = keys[' '] && car.nitro > 0;
let accel = car.accel;
let max = car.maxSpeed;
let currentFriction = car.friction;
let turnF = car.turnFriction;
if(isBoosting){ car.boostTime--; accel *= 2; max *= 1.8; }
if(isNitro){ accel *= 3; max *= 2.5; car.nitro -= 0.9; }
else car.nitro = Math.min(100, car.nitro + 0.35);
nitroFill.style.width = car.nitro + "%";
if(keys['ArrowUp']) car.speed += accel;
if(keys['ArrowDown']) car.speed -= accel;
const turning = keys['ArrowLeft'] || keys['ArrowRight'];
if(keys['ArrowLeft']) car.angle -= car.turnRate * (car.speed > 0 ? 1 : -1);
if(keys['ArrowRight']) car.angle += car.turnRate * (car.speed > 0 ? 1 : -1);
// Terrain detection & interactions
let onMud = false, onIce = false, onSlow = false;
for(let i = placed.length - 1; i >= 0; i--){
const o = placed[i];
// approximate hit tests:
if(o.type === 'wall'){
// axis-aligned rotated rectangle check (simple bounding box because walls small)
const dx = Math.abs(car.x - o.x);
const dy = Math.abs(car.y - o.y);
const rw = (o.w||40)/2 + 12, rh = (o.h||12)/2 + 12;
if(dx < rw && dy < rh){
// bounce off
car.speed *= -0.45;
car.x -= Math.cos(car.angle) * 12;
car.y -= Math.sin(car.angle) * 12;
}
} else {
const dx = car.x - o.x, dy = car.y - o.y;
const dist = Math.hypot(dx,dy);
const radius = (o.r||20) + 12;
if(dist < radius){
if(o.type === 'boost'){ car.boostTime = Math.max(car.boostTime, 160); }
if(o.type === 'mud'){ onMud = true; }
if(o.type === 'ice'){ onIce = true; }
if(o.type === 'slow'){ onSlow = true; }
if(o.type === 'stop'){ car.speed = 0; }
if(o.type === 'boom' && !o.broken){
// explode: remove explosive and spawn explosion
o.broken = true;
// remove object
placed.splice(i,1);
// compute direction from explosion center to car, push car away
const vx = car.x - o.x, vy = car.y - o.y;
const ang = Math.atan2(vy, vx);
car.angle = ang;
car.speed = Math.min(18, 8 + Math.hypot(vx,vy) * 0.06);
spawnExplosion(o.x, o.y);
}
}
}
}
// terrain modifications
if(onIce){ currentFriction = 0; turnF = 0.005; }
if(onMud){ currentFriction = Math.max(currentFriction, 0.04); max *= 0.65; }
if(onSlow){ currentFriction += 0.03; max *= 0.6; }
// More sliding when turning: reduce speed a bit when steering to create slide feeling
if(turning) car.speed *= (1 - turnF);
else car.speed *= (1 - currentFriction);
if(car.speed > max) car.speed = max;
if(car.speed < -max/2) car.speed = -max/2;
car.x += Math.cos(car.angle) * car.speed;
car.y += Math.sin(car.angle) * car.speed;
// wrap
if(car.x < 0) car.x = canvas.width;
if(car.x > canvas.width) car.x = 0;
if(car.y < 0) car.y = canvas.height;
if(car.y > canvas.height) car.y = 0;
// trails + mud trail
const backOffset = 20;
const isHot = isBoosting || isNitro;
const leftTrail = {
x: car.x - Math.cos(car.angle) * backOffset + Math.sin(car.angle) * 6,
y: car.y - Math.sin(car.angle) * backOffset - Math.cos(car.angle) * 6,
life: 1, heat: isHot ? 1 : 0,
color: isHot ? '#ff0000' : '#000'
};
const rightTrail = {
x: car.x - Math.cos(car.angle) * backOffset - Math.sin(car.angle) * 6,
y: car.y - Math.sin(car.angle) * backOffset + Math.cos(car.angle) * 6,
life: 1, heat: isHot ? 1 : 0,
color: isHot ? '#ff0000' : '#000'
};
trails.push(leftTrail, rightTrail);
if(onMud) mudTrail.push({x:car.x, y:car.y, life:1});
if(trails.length > 1200) trails.splice(0, 2);
if(mudTrail.length > 800) mudTrail.splice(0, 4);
}
// === Draw routines ===
function drawCar(x,y,a){
ctx.save();
ctx.translate(x,y);
ctx.rotate(a);
// body
ctx.fillStyle = '#ff4d4d';
ctx.strokeStyle = '#222';
ctx.lineWidth = 3;
roundRect(ctx, -15, -10, 30, 20, 5, true, true);
// window
ctx.fillStyle = '#66ccff';
roundRect(ctx, -10, -7, 20, 7, 2, true, false);
ctx.restore();
}
function roundRect(ctx, x, y, w, h, r, fill, stroke){
if (typeof r === 'undefined') r = 5;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
if(fill) ctx.fill();
if(stroke) ctx.stroke();
}
// draw placed objects, ghost, explosions, trails
function drawObjects(){
// placed
for(const o of placed){
ctx.save();
if(o.type === 'wall'){
ctx.translate(o.x, o.y);
ctx.rotate(o.angle || 0);
ctx.fillStyle = '#444';
ctx.fillRect(-(o.w||40)/2, -(o.h||12)/2, o.w||40, o.h||12);
} else if(o.type === 'boost'){
ctx.fillStyle = '#00ff88';
ctx.beginPath(); ctx.arc(o.x, o.y, o.r||20, 0, Math.PI*2); ctx.fill();
} else if(o.type === 'mud'){
ctx.fillStyle = '#6b4b2a';
ctx.beginPath(); ctx.arc(o.x, o.y, o.r||26, 0, Math.PI*2); ctx.fill();
} else if(o.type === 'ice'){
ctx.fillStyle = '#bfe8ff';
ctx.beginPath(); ctx.arc(o.x, o.y, o.r||26, 0, Math.PI*2); ctx.fill();
} else if(o.type === 'slow'){
ctx.fillStyle = '#fdd835';
ctx.beginPath(); ctx.arc(o.x, o.y, o.r||20, 0, Math.PI*2); ctx.fill();
} else if(o.type === 'boom'){
ctx.fillStyle = '#ff3333';
ctx.beginPath(); ctx.arc(o.x, o.y, o.r||20, 0, Math.PI*2); ctx.fill();
// little center
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(o.x, o.y, 4, 0, Math.PI*2); ctx.fill();
} else if(o.type === 'stop'){
ctx.fillStyle = '#000';
ctx.beginPath(); ctx.arc(o.x, o.y, o.r||18, 0, Math.PI*2); ctx.fill();
}
ctx.restore();
}
// ghost preview
if(ghost){
ctx.save();
ctx.globalAlpha = 0.45;
if(placementMode === 'area' && areaStart){
// draw rectangle area between areaStart and current mouse
const x1 = Math.min(areaStart.x, mouse.x);
const y1 = Math.min(areaStart.y, mouse.y);
const x2 = Math.max(areaStart.x, mouse.x);
const y2 = Math.max(areaStart.y, mouse.y);
ctx.fillStyle = '#b0b0b0';
ctx.fillRect(x1, y1, x2 - x1, y2 - y1);
} else {
if(ghost.type === 'wall'){
ctx.translate(ghost.x, ghost.y);
ctx.rotate(ghost.angle || 0);
ctx.fillStyle = '#888';
ctx.fillRect(-20, -6, 40, 12);
} else {
ctx.fillStyle = '#888';
ctx.beginPath(); ctx.arc(ghost.x, ghost.y, placementCellSizeFor(ghost.type)/2 - 4, 0, Math.PI*2); ctx.fill();
}
}
ctx.restore();
}
// explosions
for(const ex of explosions){
ctx.save();
const alpha = ex.life;
const r = ex.r;
// expanding ring
ctx.globalAlpha = Math.min(0.6, alpha*0.6);
ctx.fillStyle = 'rgba(255,140,0,0.9)';
ctx.beginPath();
ctx.arc(ex.x, ex.y, r/2, 0, Math.PI*2);
ctx.fill();
// ring
ctx.globalAlpha = Math.max(0, alpha);
ctx.strokeStyle = `rgba(255,120,0,${alpha})`;
ctx.lineWidth = 6 * alpha;
ctx.beginPath();
ctx.arc(ex.x, ex.y, r, 0, Math.PI*2);
ctx.stroke();
ctx.restore();
}
}
// draw trails and mud trail
function drawTrails(){
for(const t of trails){
if(t.heat > 0){
let c = '#ff0000';
if(t.heat < 0.66 && t.heat >= 0.33) c = '#ff7f00';
if(t.heat < 0.33) c = '#ffff00';
ctx.fillStyle = c;
} else ctx.fillStyle = t.color;
ctx.globalAlpha = t.life * 0.28;
ctx.beginPath();
ctx.arc(t.x, t.y, 2.2, 0, Math.PI*2);
ctx.fill();
ctx.globalAlpha = 1;
t.life -= 0.014;
if(t.heat > 0) t.heat -= 0.02;
}
for(const m of mudTrail){
ctx.fillStyle = '#6b4b2a';
ctx.globalAlpha = Math.min(0.6, m.life * 0.9);
ctx.beginPath();
ctx.arc(m.x, m.y, 3.5, 0, Math.PI*2);
ctx.fill();
ctx.globalAlpha = 1;
m.life -= 0.008;
}
}
// === Main loop ===
function loop(){
ctx.clearRect(0,0,canvas.width,canvas.height);
updateCar();
drawTrails();
drawObjects();
drawCar(car.x, car.y, car.angle);
// update explosions
for(let i = explosions.length - 1; i >= 0; i--){
const ex = explosions[i];
ex.r += (ex.maxR / 30);
ex.life -= 0.04;
if(ex.life <= 0) explosions.splice(i,1);
}
requestAnimationFrame(loop);
}
loop();
// === Helpers & resize ===
window.addEventListener('resize', ()=>{ canvas.width = innerWidth; canvas.height = innerHeight; });
// utility: approx point in rect (used earlier maybe)
/* nothing extra */
// End script
})();