From d00ba8cc400d38b7f230f6f162553064a5701eb8 Mon Sep 17 00:00:00 2001 From: anshk Date: Fri, 3 Apr 2026 19:07:24 +0530 Subject: [PATCH] feat: added task4 in vanilla --- Week-2/Task-4/vanilla/index.html | 106 ++++++++++++++++++++ Week-2/Task-4/vanilla/main.js | 166 +++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/Week-2/Task-4/vanilla/index.html b/Week-2/Task-4/vanilla/index.html index ff80367..f2183c1 100644 --- a/Week-2/Task-4/vanilla/index.html +++ b/Week-2/Task-4/vanilla/index.html @@ -5,13 +5,119 @@ Task4 vanilla +
+

Task 4: Group Motion

+

+

+ +
+ + + +
+ +
+ + +
+ +

Simple parent group animation. Keys: 1, 2, 3.

+
diff --git a/Week-2/Task-4/vanilla/main.js b/Week-2/Task-4/vanilla/main.js index e69de29..66e11ee 100644 --- a/Week-2/Task-4/vanilla/main.js +++ b/Week-2/Task-4/vanilla/main.js @@ -0,0 +1,166 @@ +import * as THREE from 'three' + +const scene = new THREE.Scene() +scene.background = new THREE.Color(0xedf3fa) + +const camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 100) + +const renderer = new THREE.WebGLRenderer({ antialias: true }) +renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) +renderer.setSize(window.innerWidth, window.innerHeight) +document.body.appendChild(renderer.domElement) + +scene.add(new THREE.AmbientLight(0xffffff, 0.8)) + +const keyLight = new THREE.DirectionalLight(0xffffff, 1) +keyLight.position.set(4, 5, 4) +scene.add(keyLight) + +const floor = new THREE.Mesh( + new THREE.PlaneGeometry(12, 12), + new THREE.MeshStandardMaterial({ color: 0xdde7f3, roughness: 0.95 }) +) +floor.rotation.x = -Math.PI / 2 +floor.position.y = -1.2 +scene.add(floor) + +const parentGroup = new THREE.Group() + +const leftBox = new THREE.Mesh( + new THREE.BoxGeometry(0.9, 0.9, 0.9), + new THREE.MeshStandardMaterial({ color: 0x2a9d8f }) +) +leftBox.position.x = -1.1 + +const rightSphere = new THREE.Mesh( + new THREE.SphereGeometry(0.55, 24, 24), + new THREE.MeshStandardMaterial({ color: 0xe76f51 }) +) +rightSphere.position.x = 1.1 + +const topCone = new THREE.Mesh( + new THREE.ConeGeometry(0.42, 0.85, 24), + new THREE.MeshStandardMaterial({ color: 0x457b9d }) +) +topCone.position.set(0, 0.95, 0) + +parentGroup.add(leftBox, rightSphere, topCone) +scene.add(parentGroup) + +const STEPS = [ + { + label: 'Step 1: Group at rest', + detail: 'Parent group is centered and children keep their offsets.', + cameraPosition: [0, 1.7, 6], + lookAt: [0, 0, 0], + groupPosition: [0, 0, 0], + groupRotation: [0, 0, 0], + spinSpeed: 0, + }, + { + label: 'Step 2: Parent rotation', + detail: 'Only parent rotates; children move together without changing local layout.', + cameraPosition: [1.7, 1.8, 5.6], + lookAt: [0, 0, 0], + groupPosition: [0, 0, 0], + groupRotation: [0.15, 0.55, 0], + spinSpeed: 0.015, + }, + { + label: 'Step 3: Parent move + rotate', + detail: 'Parent shifts and rotates as one unit while child spacing stays intact.', + cameraPosition: [0.6, 2.4, 7], + lookAt: [0.4, 0.35, 0], + groupPosition: [0.7, 0.4, -0.4], + groupRotation: [0.35, 1.2, 0.2], + spinSpeed: 0.03, + }, +] + +const targets = { + cameraPosition: new THREE.Vector3(), + cameraLookAt: new THREE.Vector3(), + lookCurrent: new THREE.Vector3(), + groupPosition: new THREE.Vector3(), + groupRotation: new THREE.Euler(), +} + +let currentStepIndex = 0 +let spinSpeed = 0 +let initialized = false + +const stepLabel = document.getElementById('step-label') +const stepDetail = document.getElementById('step-detail') +const stepButtons = Array.from(document.querySelectorAll('.step-btn')) +const prevButton = document.getElementById('prev-btn') +const nextButton = document.getElementById('next-btn') + +function applyStep(stepIndex) { + currentStepIndex = THREE.MathUtils.clamp(stepIndex, 0, STEPS.length - 1) + const step = STEPS[currentStepIndex] + + targets.cameraPosition.set(...step.cameraPosition) + targets.cameraLookAt.set(...step.lookAt) + targets.groupPosition.set(...step.groupPosition) + targets.groupRotation.set(...step.groupRotation) + spinSpeed = step.spinSpeed + + if (!initialized) { + camera.position.copy(targets.cameraPosition) + targets.lookCurrent.copy(targets.cameraLookAt) + parentGroup.position.copy(targets.groupPosition) + parentGroup.rotation.copy(targets.groupRotation) + initialized = true + } + + stepLabel.textContent = step.label + stepDetail.textContent = step.detail + + stepButtons.forEach((button, index) => { + button.classList.toggle('active', index === currentStepIndex) + }) + + prevButton.disabled = currentStepIndex === 0 + nextButton.disabled = currentStepIndex === STEPS.length - 1 +} + +stepButtons.forEach((button) => { + button.addEventListener('click', () => { + applyStep(Number(button.dataset.step)) + }) +}) + +prevButton.addEventListener('click', () => applyStep(currentStepIndex - 1)) +nextButton.addEventListener('click', () => applyStep(currentStepIndex + 1)) + +window.addEventListener('keydown', (event) => { + if (event.key === '1') applyStep(0) + if (event.key === '2') applyStep(1) + if (event.key === '3') applyStep(2) +}) + +applyStep(0) + +function animate() { + parentGroup.position.lerp(targets.groupPosition, 0.1) + + parentGroup.rotation.x += (targets.groupRotation.x - parentGroup.rotation.x) * 0.1 + parentGroup.rotation.y += (targets.groupRotation.y - parentGroup.rotation.y) * 0.1 + parentGroup.rotation.z += (targets.groupRotation.z - parentGroup.rotation.z) * 0.1 + + parentGroup.rotation.y += spinSpeed * 0.2 + + camera.position.lerp(targets.cameraPosition, 0.08) + targets.lookCurrent.lerp(targets.cameraLookAt, 0.08) + camera.lookAt(targets.lookCurrent) + + renderer.render(scene, camera) +} + +renderer.setAnimationLoop(animate) + +window.addEventListener('resize', () => { + camera.aspect = window.innerWidth / window.innerHeight + camera.updateProjectionMatrix() + renderer.setSize(window.innerWidth, window.innerHeight) +})