From 49c832318f8197acfc55956e16921bee77275929 Mon Sep 17 00:00:00 2001 From: anshk Date: Thu, 2 Apr 2026 19:44:16 +0530 Subject: [PATCH] feat: added task3 in vanilla --- Week-2/Task-3/vanilla/index.html | 103 +++++++++++++++++- Week-2/Task-3/vanilla/main.js | 163 +++++++++++++++++++++++++++++ Week-2/Task-3/vanilla/package.json | 6 ++ 3 files changed, 271 insertions(+), 1 deletion(-) diff --git a/Week-2/Task-3/vanilla/index.html b/Week-2/Task-3/vanilla/index.html index 9bc8e83..43eab5e 100644 --- a/Week-2/Task-3/vanilla/index.html +++ b/Week-2/Task-3/vanilla/index.html @@ -12,12 +12,113 @@ width: 100%; height: 100%; overflow: hidden; - background: #101418; + background: #eaf0f7; + font-family: "Avenir Next", "Segoe UI", sans-serif; + } + + canvas { + display: block; + width: 100%; + height: 100%; + } + + #guide { + position: fixed; + top: 14px; + left: 14px; + z-index: 10; + max-width: 290px; + background: rgba(255, 255, 255, 0.88); + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 10px; + padding: 10px; + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); + display: flex; + flex-direction: column; + gap: 8px; + } + + #guide h2 { + margin: 0; + font-size: 14px; + color: #203448; + } + + #step-label { + margin: 0; + font-size: 13px; + font-weight: 700; + color: #1b2530; + } + + #step-detail { + margin: 0; + font-size: 12px; + color: #4f647a; + line-height: 1.35; + } + + .row { + display: flex; + gap: 6px; + flex-wrap: wrap; + } + + button { + border: 1px solid #cfd8e3; + background: #fff; + color: #203448; + border-radius: 8px; + padding: 7px 9px; + font-size: 12px; + cursor: pointer; + transition: all 0.2s ease; + } + + button:hover { + border-color: #8ea2b8; + transform: translateY(-1px); + } + + button.active { + background: #203448; + border-color: #203448; + color: #f4f8fb; + } + + button:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; + } + + #hint { + margin: 0; + font-size: 11px; + color: #566f86; } +
+

Step Guided Flow

+

+

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

Use buttons or keys 1, 2, 3.

+
diff --git a/Week-2/Task-3/vanilla/main.js b/Week-2/Task-3/vanilla/main.js index e69de29..91a5b68 100644 --- a/Week-2/Task-3/vanilla/main.js +++ b/Week-2/Task-3/vanilla/main.js @@ -0,0 +1,163 @@ +import * as THREE from 'three' + +const scene = new THREE.Scene() +scene.background = new THREE.Color(0xeaf0f7) + +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 dirLight = new THREE.DirectionalLight(0xffffff, 1) +dirLight.position.set(3, 4, 5) +scene.add(dirLight) + +const floor = new THREE.Mesh( + new THREE.PlaneGeometry(12, 12), + new THREE.MeshStandardMaterial({ color: 0xdbe6f3, roughness: 0.95 }) +) +floor.rotation.x = -Math.PI / 2 +floor.position.y = -0.8 +scene.add(floor) + +const objectA = new THREE.Mesh( + new THREE.BoxGeometry(1.2, 1.2, 1.2), + new THREE.MeshStandardMaterial({ color: 0x2a9d8f }) +) + +const objectB = new THREE.Mesh( + new THREE.SphereGeometry(0.7, 32, 32), + new THREE.MeshStandardMaterial({ color: 0xe76f51 }) +) + +scene.add(objectA, objectB) + +const STEPS = [ + { + label: 'Step 1: Focus on object A', + detail: 'Camera frames object A only.', + cameraPosition: [0, 1.4, 5], + lookAt: [-1.2, 0, 0], + a: { position: [-1.2, 0, 0], rotation: [0, 0.25, 0], visible: true }, + b: { position: [1.4, 0, 0], rotation: [0, 0, 0], visible: false }, + }, + { + label: 'Step 2: Move camera + reveal object B', + detail: 'Camera shifts right and object B becomes visible.', + cameraPosition: [2.2, 1.4, 5], + lookAt: [1.4, 0, 0], + a: { position: [-1.2, 0, 0], rotation: [0.2, 0.8, 0], visible: true }, + b: { position: [1.4, 0, 0], rotation: [0, 0.2, 0], visible: true }, + }, + { + label: 'Step 3: Final combined scene', + detail: 'Both objects stay visible in one balanced view.', + cameraPosition: [0.3, 2.2, 7], + lookAt: [0, 0, 0], + a: { position: [-1.5, 0, 0], rotation: [0.3, 1.1, 0], visible: true }, + b: { position: [1.5, 0, 0], rotation: [0.1, 0.6, 0], visible: true }, + }, +] + +const targets = { + cameraPosition: new THREE.Vector3(), + cameraLookAt: new THREE.Vector3(), + aPosition: new THREE.Vector3(), + aRotation: new THREE.Euler(), + bPosition: new THREE.Vector3(), + bRotation: new THREE.Euler(), +} + +let currentStep = 0 +let initialized = false +const lookCurrent = new THREE.Vector3() + +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(index) { + currentStep = THREE.MathUtils.clamp(index, 0, STEPS.length - 1) + const step = STEPS[currentStep] + + targets.cameraPosition.set(...step.cameraPosition) + targets.cameraLookAt.set(...step.lookAt) + + targets.aPosition.set(...step.a.position) + targets.aRotation.set(...step.a.rotation) + objectA.visible = step.a.visible + + targets.bPosition.set(...step.b.position) + targets.bRotation.set(...step.b.rotation) + objectB.visible = step.b.visible + + if (!initialized) { + camera.position.copy(targets.cameraPosition) + lookCurrent.copy(targets.cameraLookAt) + objectA.position.copy(targets.aPosition) + objectA.rotation.copy(targets.aRotation) + objectB.position.copy(targets.bPosition) + objectB.rotation.copy(targets.bRotation) + initialized = true + } + + stepLabel.textContent = step.label + stepDetail.textContent = step.detail + + stepButtons.forEach((button, buttonIndex) => { + button.classList.toggle('active', buttonIndex === currentStep) + }) + + prevButton.disabled = currentStep === 0 + nextButton.disabled = currentStep === STEPS.length - 1 +} + +stepButtons.forEach((button) => { + button.addEventListener('click', () => applyStep(Number(button.dataset.step))) +}) + +prevButton.addEventListener('click', () => applyStep(currentStep - 1)) +nextButton.addEventListener('click', () => applyStep(currentStep + 1)) + +window.addEventListener('keydown', (event) => { + if (event.key === '1') applyStep(0) + if (event.key === '2') applyStep(1) + if (event.key === '3') applyStep(2) + if (event.key === 'ArrowLeft') applyStep(currentStep - 1) + if (event.key === 'ArrowRight') applyStep(currentStep + 1) +}) + +applyStep(0) + +function animate() { + objectA.position.lerp(targets.aPosition, 0.1) + objectB.position.lerp(targets.bPosition, 0.1) + + objectA.rotation.x += (targets.aRotation.x - objectA.rotation.x) * 0.1 + objectA.rotation.y += (targets.aRotation.y - objectA.rotation.y) * 0.1 + objectA.rotation.z += (targets.aRotation.z - objectA.rotation.z) * 0.1 + + objectB.rotation.x += (targets.bRotation.x - objectB.rotation.x) * 0.1 + objectB.rotation.y += (targets.bRotation.y - objectB.rotation.y) * 0.1 + objectB.rotation.z += (targets.bRotation.z - objectB.rotation.z) * 0.1 + + camera.position.lerp(targets.cameraPosition, 0.08) + lookCurrent.lerp(targets.cameraLookAt, 0.08) + camera.lookAt(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) +}) diff --git a/Week-2/Task-3/vanilla/package.json b/Week-2/Task-3/vanilla/package.json index ba20654..72e838a 100644 --- a/Week-2/Task-3/vanilla/package.json +++ b/Week-2/Task-3/vanilla/package.json @@ -8,5 +8,11 @@ "build": "vite build", "lint": "echo 'Add your lint script here'", "clean": "rm -rf dist build" + }, + "dependencies": { + "three": "^0.183.2" + }, + "devDependencies": { + "vite": "^8.0.3" } } \ No newline at end of file