What’s on our mind?

Collection of articles, design, site, and resources made by designers and publisher @Menu View


const canvas = document.querySelector('.webgl');

const degreesToRadians = (degrees) => {
    return degrees * (Math.PI / 180)
}

const random = (min, max, float = false) => {
    const val = Math.random() * (max - min) + min
    if (float) {
        return val
    }
    return Math.floor(val)
}

// 화면 설정
const scene = new THREE.Scene();

// 렌더러 설정
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio > 1 ? 2 : 1);
renderer.setSize(window.innerWidth, window.innerHeight);

// 카메라 설정
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5
scene.add(camera);

// 메쉬 설정
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({ color: 0xffffff });
const mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = degreesToRadians(30)
mesh.rotation.y = degreesToRadians(30)  
// scene.add(mesh);

// 조명 설정
const lightDirectional = new THREE.DirectionalLight(0xffffff, 1);
lightDirectional.position.set(5, 5, 5)
scene.add(lightDirectional);

const lightAmbient = new THREE.AmbientLight(0x9eaeff, 0.2)
scene.add(lightAmbient)


// Figure
class Figure {
    constructor(params) {
        this.params = {
            x: 0,
            y: 0,
            z: 0,
            ry: 0,
            ...params
        }

        this.group = new THREE.Group();
        this.group.rotation.y = degreesToRadians(20)
        scene.add(this.group);

        this.group.position.x = this.params.x
        this.group.position.y = this.params.y
        this.group.position.z = this.params.z

        this.headHue = random(0, 360)
        this.bodyHue = random(0, 360)
        this.headLightness = random(40, 65)
        this.headMaterial = new THREE.MeshLambertMaterial({ color: `hsl(${this.headHue}, 30%, ${this.headLightness}%)` })
        this.bodyMaterial = new THREE.MeshLambertMaterial({ color: `hsl(${this.bodyHue}, 85%, 50%)` })
        
        this.arms = []
    }
    createBody() {
        this.body = new THREE.Group()
        const geometry = new THREE.BoxGeometry(1, 1.5, 1)
        const bodyMain = new THREE.Mesh(geometry, this.bodyMaterial)
        
        this.body.add(bodyMain)
        this.group.add(this.body)
        
        this.createLegs()
    }

    createHead() {
        this.head = new THREE.Group()

        const geometry = new THREE.BoxGeometry(1.4, 1.4, 1.4)
        const headMain = new THREE.Mesh(geometry, material)
        this.head.add(headMain)

        this.group.add(this.head);

        this.head.position.y = 1.65;
        
        this.createEyes()
    }

    createArms() {
        const height = 0.85
        
        for(let i = 0; i < 2; i++) {
            const armGroup = new THREE.Group()
            const geometry = new THREE.BoxGeometry(0.25, height, 0.25)
            const arm = new THREE.Mesh(geometry, material)
            const m = i % 2 === 0 ? 1 : -1
            
            armGroup.add(arm)
        
            this.body.add(armGroup)
            
            arm.position.y = height * -0.5
            armGroup.position.x = m * 0.8
            armGroup.position.y = 0.6
            armGroup.rotation.z = degreesToRadians(30 * m)
            
            this.arms.push(armGroup)
        }
    }

    createEyes() {
        const eyes = new THREE.Group()
        const geometry = new THREE.SphereGeometry(0.15, 12, 8)
        
        // Define the eye material
        const material = new THREE.MeshLambertMaterial({ color: 0x44445c })
        
        for(let i = 0; i < 2; i++) {
            const eye = new THREE.Mesh(geometry, material)
            const m = i % 2 === 0 ? 1 : -1
            
            // Add the eye to the group
            eyes.add(eye)
            
            // Position the eye
            eye.position.x = 0.36 * m
        }

        this.head.add(eyes)
        eyes.position.z = 0.7
    }

    createLegs() {
        const legs = new THREE.Group()
        const geometry = new THREE.BoxGeometry(0.25, 0.4, 0.25)
        
        for(let i = 0; i < 2; i++) {
            const leg = new THREE.Mesh(geometry, material)
            const m = i % 2 === 0 ? 1 : -1
            
            legs.add(leg)
            leg.position.x = m * 0.22
        }
        
        this.group.add(legs)
        legs.position.y = -1.15
        
        this.body.add(legs)
    }

    bounce() {
        this.group.rotation.y = this.params.ry
        this.group.position.y = this.params.y
        this.arms.forEach((arm, index) => {
            const m = index % 2 === 0 ? 1 : -1
            arm.rotation.z = this.params.armRotation * m
        })
    }

    init() {
        this.createHead();
        this.createBody();
        this.createArms();
        this.createEyes();
        this.createLegs();
    }
}

const figure = new Figure()
figure.init();

gsap.set(figure.params, {
    y: -1.5
})

gsap.to(figure.params, {
    ry: degreesToRadians(360),
    repeat: -1,
    duration: 20
})

gsap.to(figure.params, {
    y: 0,
    armRotation: degreesToRadians(90),
    repeat: -1,
    yoyo: true,
    duration: 0.5
})

gsap.ticker.add(() => {
    figure.bounce()
    render()
})


// 애니메이션 설정
function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();

// 화면 사이즈 설정
function resize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', resize);