JustPaste
HomeCategoriesAboutDonateContactTerms of UsePrivacy Policy
JustPaste

Free online notepad — write and share instantly

Navigate

  • Home
  • Timeline
  • Categories

Info

  • About
  • Donate
  • Contact

Legal

  • Terms of Use
  • Privacy Policy

© 2026 JustPaste.app. All rights reserved.

Made with ♥ by JustPaste

Code | JustPaste.app
12 days ago22 views
👨‍💻Programming

Code

<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Computer Smash</title>

<style>
    html, body {
        margin: 0;
        width: 100%;
        height: 100%;
        overflow: hidden;
        background: #111;
        font-family: Arial, sans-serif;
    }

    canvas {
        display: block;
    }

    #ui {
        position: fixed;
        top: 15px;
        left: 15px;
        z-index: 10;
        color: white;
        background: rgba(0,0,0,.65);
        padding: 12px;
        border-radius: 10px;
        user-select: none;
    }

    #reset {
        margin-top: 8px;
        width: 100%;
        padding: 9px;
        border: 0;
        border-radius: 7px;
        cursor: pointer;
        font-weight: bold;
    }
</style>
</head>

<body>

<div id="ui">
    🏏 چوب را بکش و ضربه بزن
    <br>
    🖱️ برای چرخش دوربین هم بکش
    <button id="reset">RESET</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>

<script>

////////////////////////////////////////////////////
// SCENE
////////////////////////////////////////////////////

const scene = new THREE.Scene();

scene.background = new THREE.Color(0x15181c);

const camera = new THREE.PerspectiveCamera(
    60,
    innerWidth / innerHeight,
    0.1,
    100
);

camera.position.set(8, 6, 10);

const renderer = new THREE.WebGLRenderer({
    antialias: true
});

renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.shadowMap.enabled = true;

document.body.appendChild(renderer.domElement);


////////////////////////////////////////////////////
// LIGHT
////////////////////////////////////////////////////

scene.add(new THREE.HemisphereLight(
    0xffffff,
    0x333333,
    2
));

const light = new THREE.DirectionalLight(
    0xffffff,
    3
);

light.position.set(5, 10, 7);
light.castShadow = true;

scene.add(light);


////////////////////////////////////////////////////
// MATERIALS
////////////////////////////////////////////////////

const black = new THREE.MeshStandardMaterial({
    color: 0x17191d,
    roughness: .55,
    metalness: .35
});

const dark = new THREE.MeshStandardMaterial({
    color: 0x292d33,
    roughness: .45,
    metalness: .3
});

const metal = new THREE.MeshStandardMaterial({
    color: 0x666d75,
    roughness: .3,
    metalness: .8
});

const green = new THREE.MeshStandardMaterial({
    color: 0x159447,
    roughness: .5
});

const blue = new THREE.MeshStandardMaterial({
    color: 0x1976d2,
    roughness: .4
});

const screenMat = new THREE.MeshStandardMaterial({
    color: 0x07151d,
    emissive: 0x062536,
    emissiveIntensity: 1.5,
    roughness: .25
});

const white = new THREE.MeshStandardMaterial({
    color: 0xd8d8d8,
    roughness: .7
});

const wood = new THREE.MeshStandardMaterial({
    color: 0x8b542d,
    roughness: .8
});

const rubber = new THREE.MeshStandardMaterial({
    color: 0x222222,
    roughness: .9
});


////////////////////////////////////////////////////
// COMPUTER
////////////////////////////////////////////////////

const computer = new THREE.Group();
scene.add(computer);

const destructible = [];


function box(
    x, y, z,
    sx, sy, sz,
    material,
    name = "",
    parent = computer
) {

    const mesh = new THREE.Mesh(
        new THREE.BoxGeometry(sx, sy, sz),
        material
    );

    mesh.position.set(x, y, z);
    mesh.castShadow = true;
    mesh.receiveShadow = true;

    parent.add(mesh);

    if (name) {
        addDestructible(mesh, name);
    }

    return mesh;
}


function addDestructible(mesh, name) {

    destructible.push({
        mesh: mesh,
        name: name,
        originalParent: mesh.parent,
        originalPosition: mesh.position.clone(),
        originalQuaternion: mesh.quaternion.clone(),
        velocity: new THREE.Vector3(),
        angular: new THREE.Vector3(),
        broken: false
    });

    mesh.userData.destructible = true;
}


////////////////////////////////////////////////////
// PC CASE
////////////////////////////////////////////////////

const tower = new THREE.Group();
tower.position.set(-2.8, 2.2, 0);
computer.add(tower);


// main case
const caseBody = box(
    0, 0, 0,
    2.4, 4.4, 2.2,
    black,
    "PC Case",
    tower
);


// front
box(
    0, 0, 1.13,
    2.15, 4.1, .12,
    dark,
    "Front Panel",
    tower
);


// glass side
const glassMat = new THREE.MeshStandardMaterial({
    color: 0x18313c,
    transparent: true,
    opacity: .45,
    metalness: .2,
    roughness: .1
});

box(
    1.21, 0, 0,
    .08, 4.0, 2.0,
    glassMat,
    "Glass Side",
    tower
);


// power button
const power = new THREE.Mesh(
    new THREE.CylinderGeometry(.16, .16, .08, 24),
    green
);

power.rotation.x = Math.PI / 2;
power.position.set(0, 1.65, 1.22);
power.castShadow = true;
tower.add(power);

addDestructible(power, "Power Button");


// USB ports
for (let i = 0; i < 3; i++) {

    box(
        -.65 + i * .35,
        1.05,
        1.21,
        .22,
        .1,
        .05,
        blue,
        "USB Port",
        tower
    );
}


////////////////////////////////////////////////////
// MOTHERBOARD
////////////////////////////////////////////////////

box(
    .2, 0, -.9,
    1.5, 3.3, .08,
    green,
    "Motherboard",
    tower
);


// RAM
for (let i = 0; i < 3; i++) {

    box(
        -.35 + i * .32,
        .65,
        -.84,
        .15,
        1.5,
        .1,
        blue,
        "RAM",
        tower
    );
}


// CPU
box(
    .2, .3, -.84,
    .65, .65, .12,
    metal,
    "CPU",
    tower
);


// CPU cooler
const cooler = new THREE.Mesh(
    new THREE.CylinderGeometry(.38, .38, .3, 20),
    metal
);

cooler.position.set(.2, .7, -.84);
cooler.castShadow = true;
tower.add(cooler);

addDestructible(cooler, "CPU Cooler");


// GPU
box(
    .15, -.9, -.83,
    1.65, .42, .28,
    dark,
    "Graphics Card",
    tower
);


// GPU fans
for (let i = 0; i < 2; i++) {

    const fan = new THREE.Mesh(
        new THREE.CylinderGeometry(.15, .15, .04, 20),
        black
    );

    fan.rotation.x = Math.PI / 2;

    fan.position.set(
        -.25 + i * .65,
        -.9,
        -.67
    );

    fan.castShadow = true;
    tower.add(fan);

    addDestructible(fan, "GPU Fan");
}


////////////////////////////////////////////////////
// MONITOR
////////////////////////////////////////////////////

const monitor = new THREE.Group();

monitor.position.set(1.2, 2.35, 0);
computer.add(monitor);


// monitor body
box(
    0, 0, 0,
    4.7, 3.0, .45,
    black,
    "Monitor Body",
    monitor
);


// screen
box(
    0, 0, .27,
    4.25, 2.55, .08,
    screenMat,
    "Screen",
    monitor
);


// screen border
box(
    0, 1.4, .30,
    4.7, .15, .12,
    dark,
    "Top Bezel",
    monitor
);

box(
    0, -1.4, .30,
    4.7, .15, .12,
    dark,
    "Bottom Bezel",
    monitor
);


// stand
box(
    0, -2.0, 0,
    .45, 1.0, .45,
    metal,
    "Monitor Stand",
    monitor
);


// base
box(
    0, -2.55, .1,
    2.0, .18, 1.0,
    metal,
    "Monitor Base",
    monitor
);


////////////////////////////////////////////////////
// KEYBOARD
////////////////////////////////////////////////////

const keyboard = new THREE.Group();

keyboard.position.set(1.2, .35, 3);
keyboard.rotation.x = -.08;

computer.add(keyboard);

box(
    0, 0, 0,
    4.0, .25, 1.55,
    black,
    "Keyboard Body",
    keyboard
);


for (let row = 0; row < 4; row++) {

    const count = row === 3 ? 7 : 10;

    for (let col = 0; col < count; col++) {

        const key = box(
            -1.65 + col * .36,
            .18,
            -.48 + row * .32,
            .27,
            .13,
            .23,
            white,
            "Keyboard Key",
            keyboard
        );

        key.rotation.y =
            (Math.random() - .5) * .04;
    }
}


// spacebar
box(
    0, .18, .48,
    1.55, .13, .23,
    white,
    "Spacebar",
    keyboard
);


////////////////////////////////////////////////////
// MOUSE
////////////////////////////////////////////////////

const mouse = new THREE.Group();

mouse.position.set(4, .45, 3);
computer.add(mouse);

box(
    0, 0, 0,
    .85, .35, 1.35,
    dark,
    "Mouse",
    mouse
);


const wheel = new THREE.Mesh(
    new THREE.CylinderGeometry(.1, .1, .08, 16),
    white
);

wheel.rotation.z = Math.PI / 2;
wheel.position.set(0, .2, -.1);

mouse.add(wheel);
addDestructible(wheel, "Mouse Wheel");


////////////////////////////////////////////////////
// BAT
////////////////////////////////////////////////////

const bat = new THREE.Group();

scene.add(bat);

bat.position.set(
    3.8,
    2.2,
    2.7
);

bat.rotation.z = -.7;


// handle
const handle = new THREE.Mesh(
    new THREE.CylinderGeometry(
        .13,
        .16,
        2.0,
        16
    ),
    wood
);

handle.position.y = -1;

handle.castShadow = true;

bat.add(handle);


// barrel
const barrel = new THREE.Mesh(
    new THREE.CylinderGeometry(
        .28,
        .15,
        2.6,
        20
    ),
    wood
);

barrel.position.y = .9;

barrel.castShadow = true;

bat.add(barrel);


// knob
const knob = new THREE.Mesh(
    new THREE.SphereGeometry(.23, 16, 12),
    wood
);

knob.position.y = -2.0;

bat.add(knob);


////////////////////////////////////////////////////
// DESK
////////////////////////////////////////////////////

box(
    0, -.35, 0,
    13, .7, 7,
    dark,
    ""
);


// floor
const floor = new THREE.Mesh(
    new THREE.PlaneGeometry(40, 40),
    new THREE.MeshStandardMaterial({
        color: 0x303030,
        roughness: 1
    })
);

floor.rotation.x = -Math.PI / 2;
floor.position.y = -.72;
floor.receiveShadow = true;

scene.add(floor);


////////////////////////////////////////////////////
// CAMERA
////////////////////////////////////////////////////

let yaw = .7;
let pitch = .35;
let distance = 13;

const target = new THREE.Vector3(
    0,
    1.2,
    0
);


function updateCamera() {

    const cp = Math.cos(pitch);

    camera.position.x =
        target.x +
        Math.sin(yaw) * cp * distance;

    camera.position.z =
        target.z +
        Math.cos(yaw) * cp * distance;

    camera.position.y =
        target.y +
        Math.sin(pitch) * distance;

    camera.lookAt(target);
}


updateCamera();


////////////////////////////////////////////////////
// CAMERA MOUSE
////////////////////////////////////////////////////

let draggingCamera = false;
let lastX = 0;
let lastY = 0;

renderer.addEventListener("mousedown", e => {

    draggingCamera = true;

    lastX = e.clientX;
    lastY = e.clientY;
});

window.addEventListener("mouseup", () => {
    draggingCamera = false;
});

window.addEventListener("mousemove", e => {

    if (!draggingCamera) return;

    const dx = e.clientX - lastX;
    const dy = e.clientY - lastY;

    yaw -= dx * .008;
    pitch += dy * .008;

    pitch = Math.max(
        -1.35,
        Math.min(1.35, pitch)
    );

    lastX = e.clientX;
    lastY = e.clientY;

    updateCamera();
});


////////////////////////////////////////////////////
// CAMERA WHEEL
////////////////////////////////////////////////////

window.addEventListener("wheel", e => {

    distance += e.deltaY * .01;

    distance = Math.max(
        5,
        Math.min(25, distance)
    );

    updateCamera();
});


////////////////////////////////////////////////////
// BAT SWING
////////////////////////////////////////////////////

let swinging = false;

let pointerDownX = 0;
let pointerDownY = 0;
let pointerLastX = 0;
let pointerLastY = 0;

let swingVelocity = new THREE.Vector2();


function startSwing(x, y) {

    swinging = true;

    pointerDownX = x;
    pointerDownY = y;

    pointerLastX = x;
    pointerLastY = y;

    swingVelocity.set(0, 0);
}


function moveSwing(x, y) {

    if (!swinging) return;

    const dx = x - pointerLastX;
    const dy = y - pointerLastY;

    swingVelocity.set(dx, dy);

    pointerLastX = x;
    pointerLastY = y;

    // Move bat according to pointer
    bat.position.x += dx * .025;
    bat.position.y -= dy * .025;

    bat.rotation.z += dx * .025;
    bat.rotation.x += dy * .015;
}


function endSwing() {

    if (!swinging) return;

    swinging = false;

    const speed =
        swingVelocity.length();

    if (speed > 8) {

        smash();
    }
}


////////////////////////////////////////////////////
// POINTER EVENTS
////////////////////////////////////////////////////

renderer.addEventListener("mousedown", e => {

    // If mouse is close to bat screen area,
    // use it as a swing.
    const rect =
        renderer.domElement.getBoundingClientRect();

    const x =
        e.clientX - rect.left;

    const y =
        e.clientY - rect.top;

    const batScreen =
        bat.position.clone();

    batScreen.project(camera);

    const bx =
        (batScreen.x * .5 + .5) *
        rect.width;

    const by =
        (-batScreen.y * .5 + .5) *
        rect.height;

    const d =
        Math.hypot(x - bx, y - by);

    if (d < 220) {

        startSwing(
            e.clientX,
            e.clientY
        );
    }
});


window.addEventListener("mousemove", e => {

    if (swinging) {

        moveSwing(
            e.clientX,
            e.clientY
        );
    }
});


window.addEventListener("mouseup", () => {

    if (swinging) {

        endSwing();
    }
});


////////////////////////////////////////////////////
// TOUCH
////////////////////////////////////////////////////

renderer.addEventListener(
    "touchstart",
    e => {

        if (e.touches.length !== 1) return;

        const t = e.touches[0];

        startSwing(
            t.clientX,
            t.clientY
        );
    },
    {passive:false}
);


renderer.addEventListener(
    "touchmove",
    e => {

        if (!swinging) return;

        e.preventDefault();

        const t = e.touches[0];

        moveSwing(
            t.clientX,
            t.clientY
        );
    },
    {passive:false}
);


renderer.addEventListener(
    "touchend",
    () => {

        endSwing();
    }
);


////////////////////////////////////////////////////
// SMASH
////////////////////////////////////////////////////

const temp = new THREE.Vector3();

function smash() {

    // bat world position
    const batWorld =
        new THREE.Vector3();

    bat.getWorldPosition(batWorld);

    let hitSomething = false;

    for (const part of destructible) {

        if (part.broken) continue;

        const mesh = part.mesh;

        const worldPos =
            new THREE.Vector3();

        mesh.getWorldPosition(worldPos);

        const dist =
            worldPos.distanceTo(batWorld);

        if (dist < 5.0) {

            breakPart(
                part,
                batWorld
            );

            hitSomething = true;
        }
    }

    // Stronger hit can break
    // a wider group of parts
    if (!hitSomething) {

        for (const part of destructible) {

            if (part.broken) continue;

            const worldPos =
                new THREE.Vector3();

            part.mesh.getWorldPosition(worldPos);

            if (worldPos.distanceTo(batWorld) < 6.5) {

                breakPart(
                    part,
                    batWorld
                );
            }
        }
    }
}


////////////////////////////////////////////////////
// BREAK PART
////////////////////////////////////////////////////

function breakPart(part, hitPoint) {

    const mesh = part.mesh;

    if (part.broken) return;

    part.broken = true;

    // Preserve world transform
    scene.attach(mesh);

    const direction =
        mesh.position.clone()
        .sub(hitPoint);

    if (direction.length() < .1) {

        direction.set(
            Math.random() - .5,
            .5,
            Math.random() - .5
        );
    }

    direction.normalize();

    const force =
        5 + Math.random() * 7;

    part.velocity.copy(
        direction.multiplyScalar(force)
    );

    part.velocity.y +=
        2 + Math.random() * 5;

    part.angular.set(
        (Math.random() - .5) * 10,
        (Math.random() - .5) * 10,
        (Math.random() - .5) * 10
    );
}


////////////////////////////////////////////////////
// PHYSICS
////////////////////////////////////////////////////

const clock =
    new THREE.Clock();

function updatePhysics(dt) {

    for (const part of destructible) {

        if (!part.broken) continue;

        const mesh = part.mesh;

        part.velocity.y -=
            12 * dt;

        mesh.position.addScaledVector(
            part.velocity,
            dt
        );

        mesh.rotation.x +=
            part.angular.x * dt;

        mesh.rotation.y +=
            part.angular.y * dt;

        mesh.rotation.z +=
            part.angular.z * dt;


        // floor collision
        if (mesh.position.y < -.35) {

            mesh.position.y = -.35;

            part.velocity.y *= -.35;

            part.velocity.x *= .82;
            part.velocity.z *= .82;

            part.angular.multiplyScalar(.88);
        }
    }
}


////////////////////////////////////////////////////
// RESET
////////////////////////////////////////////////////

function resetComputer() {

    for (const part of destructible) {

        const mesh = part.mesh;

        part.broken = false;

        // Reattach to original parent
        part.originalParent.attach(mesh);

        mesh.position.copy(
            part.originalPosition
        );

        mesh.quaternion.copy(
            part.originalQuaternion
        );

        part.velocity.set(0, 0, 0);
        part.angular.set(0, 0, 0);
    }

    bat.position.set(
        3.8,
        2.2,
        2.7
    );

    bat.rotation.set(
        0,
        0,
        -.7
    );
}


document.getElementById("reset")
    .addEventListener(
        "click",
        resetComputer
    );


window.addEventListener(
    "keydown",
    e => {

        if (
            e.key.toLowerCase() === "r"
        ) {
            resetComputer();
        }
    }
);


////////////////////////////////////////////////////
// RESIZE
////////////////////////////////////////////////////

window.addEventListener(
    "resize",
    () => {

        camera.aspect =
            innerWidth / innerHeight;

        camera.updateProjectionMatrix();

        renderer.setSize(
            innerWidth,
            innerHeight
        );
    }
);


////////////////////////////////////////////////////
// LOOP
////////////////////////////////////////////////////

function animate() {

    requestAnimationFrame(animate);

    const dt =
        Math.min(
            clock.getDelta(),
            .033
        );

    updatePhysics(dt);

    renderer.render(
        scene,
        camera
    );
}

animate();

</script>

</body>
</html>

⚠️Content was pasted as plain text and auto-formatted as a code block. Use the Code Block button in the editor for proper formatting.

← Back to timeline