diff --git a/Week-3/GeneralNotes.md b/Week-3/GeneralNotes.md new file mode 100644 index 0000000..e69de29 diff --git a/Week-3/Task-1/r3f/.gitignore b/Week-3/Task-1/r3f/.gitignore new file mode 100644 index 0000000..54f07af --- /dev/null +++ b/Week-3/Task-1/r3f/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? \ No newline at end of file diff --git a/Week-3/Task-1/r3f/README.md b/Week-3/Task-1/r3f/README.md new file mode 100644 index 0000000..57cb1aa --- /dev/null +++ b/Week-3/Task-1/r3f/README.md @@ -0,0 +1,10 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler \ No newline at end of file diff --git a/Week-3/Task-1/r3f/eslint.config.js b/Week-3/Task-1/r3f/eslint.config.js new file mode 100644 index 0000000..0cf397c --- /dev/null +++ b/Week-3/Task-1/r3f/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) \ No newline at end of file diff --git a/Week-3/Task-1/r3f/index.html b/Week-3/Task-1/r3f/index.html new file mode 100644 index 0000000..a1c874e --- /dev/null +++ b/Week-3/Task-1/r3f/index.html @@ -0,0 +1,13 @@ + + + + + + + r3f + + +
+ + + \ No newline at end of file diff --git a/Week-3/Task-1/r3f/package.json b/Week-3/Task-1/r3f/package.json new file mode 100644 index 0000000..5af5113 --- /dev/null +++ b/Week-3/Task-1/r3f/package.json @@ -0,0 +1,31 @@ +{ + "name": "week3-task1-r3f", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@react-three/drei": "9.105.6", + "@react-three/fiber": "^9.5.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "three": "^0.183.2" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "@eslint/js": "^9.39.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } +} \ No newline at end of file diff --git a/Week-3/Task-1/r3f/src/App.css b/Week-3/Task-1/r3f/src/App.css new file mode 100644 index 0000000..d87f28f --- /dev/null +++ b/Week-3/Task-1/r3f/src/App.css @@ -0,0 +1,41 @@ +.app-container { + width: 100vw; + height: 100vh; + position: relative; + background-color: white; + overflow: hidden; +} + +#controls { + position: absolute; + top: 20px; + left: 20px; + z-index: 10; + display: flex; + gap: 10px; +} + +button { + padding: 8px 16px; + cursor: pointer; + background: #f0f0f0; + border: 1px solid #ccc; + border-radius: 4px; + font-weight: 500; + transition: all 0.2s; +} + +button:hover { + background: #e0e0e0; +} + +button.active { + background: #333; + color: white; + border-color: #333; +} + +.canvas-wrapper { + width: 100%; + height: 100%; +} diff --git a/Week-3/Task-1/r3f/src/App.jsx b/Week-3/Task-1/r3f/src/App.jsx new file mode 100644 index 0000000..557d2f4 --- /dev/null +++ b/Week-3/Task-1/r3f/src/App.jsx @@ -0,0 +1,55 @@ +import React, { useState } from 'react'; +import { Canvas } from '@react-three/fiber'; +import { OrbitControls, PerspectiveCamera } from '@react-three/drei'; +import './App.css'; + +const materials = { + black: { color: "black", roughness: 1, metalness: 0 }, + silver: { color: "#C0C0C0", roughness: 0.3, metalness: 1 }, + gold: { color: "#FFD700", roughness: 0.4, metalness: 1 }, +}; + +function Scene({ variant }) { + return ( + <> + + + + + + + + + + + + + ); +} + +export default function App() { + const [activeVariant, setActiveVariant] = useState('black'); + + return ( +
+
+ {Object.keys(materials).map((variant) => ( + + ))} +
+ +
+ + + + +
+
+ ); +} \ No newline at end of file diff --git a/Week-3/Task-1/r3f/src/main.jsx b/Week-3/Task-1/r3f/src/main.jsx new file mode 100644 index 0000000..e42f191 --- /dev/null +++ b/Week-3/Task-1/r3f/src/main.jsx @@ -0,0 +1,8 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App.jsx' +createRoot(document.getElementById('root')).render( + + + , +) \ No newline at end of file diff --git a/Week-3/Task-1/r3f/vite.config.js b/Week-3/Task-1/r3f/vite.config.js new file mode 100644 index 0000000..8d60bf7 --- /dev/null +++ b/Week-3/Task-1/r3f/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) \ No newline at end of file diff --git a/Week-3/Task-1/report.md b/Week-3/Task-1/report.md new file mode 100644 index 0000000..c591b6c --- /dev/null +++ b/Week-3/Task-1/report.md @@ -0,0 +1 @@ +# Task 1 Report diff --git a/Week-3/Task-1/thob/notes.md b/Week-3/Task-1/thob/notes.md new file mode 100644 index 0000000..f29027c --- /dev/null +++ b/Week-3/Task-1/thob/notes.md @@ -0,0 +1,22 @@ +# Thob Builder Notes: Task 1 - Material Variant Switcher + +## Overview +Implemented the basic material configuration pattern using Thob's built-in `MaterialVariant` and `Material` properties. + +## Visual Observations +- **Lighting Limitation**: I observed that by default, the light only hits the object from one side, leaving the other side completely dark. +- **Surface Definition**: Standard material properties (color, roughness, metalness) were easy to edit via the sidebar properties panel. + +## Technical Observations (Console Logs) +During development in the builder, several warnings and errors were observed: +- **404 Errors**: `GET https://builder.thob.studio/builder/... 404 (Not Found)`. +- **Hydration Warnings**: `No HydrateFallback element provided to render during initial hydration`. +- **Component State**: `undefined is changing from uncontrolled to controlled`. This suggests a potential issue in how the builder manages internal component state when swapping materials. + +## Builder Workflow +- **Node Structure**: The scene was built using a `Canvas` -> `mesh` -> `sphereGeometry` hierarchy. +- **Variant Linking**: A `MaterialVariant` node was used to manage the switching logic. +- **UI Integration**: A simple `Button` was added under the `UI` group to trigger the material change. + +## Conclusion +The builder makes it very easy to define and link material variants without writing code, but the default lighting environment needs more control (e.g., adding more lights or an environment map) to avoid the "dark side" effect. diff --git a/Week-3/Task-1/vanilla/index.html b/Week-3/Task-1/vanilla/index.html new file mode 100644 index 0000000..3e7a905 --- /dev/null +++ b/Week-3/Task-1/vanilla/index.html @@ -0,0 +1,17 @@ + + + + + Material Variant Switcher + + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/Week-3/Task-1/vanilla/main.js b/Week-3/Task-1/vanilla/main.js new file mode 100644 index 0000000..7e3da1e --- /dev/null +++ b/Week-3/Task-1/vanilla/main.js @@ -0,0 +1,80 @@ +import * as THREE from "three"; +import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; + +const scene = new THREE.Scene(); +scene.background = new THREE.Color("white"); + +const camera = new THREE.PerspectiveCamera( + 75, + window.innerWidth / window.innerHeight, + 0.1, + 1000 +); +camera.position.z = 5; + +const renderer = new THREE.WebGLRenderer(); +renderer.setSize(window.innerWidth, window.innerHeight); +document.body.appendChild(renderer.domElement); + +const geometry = new THREE.TorusKnotGeometry(1.5, 0.5, 100, 16); + +const materials = { + black: new THREE.MeshStandardMaterial({ + color: "black", + roughness: 1, + metalness: 0, + }), + silver: new THREE.MeshStandardMaterial({ + color: "#C0C0C0", + roughness: 0.3, + metalness: 1, + }), + gold: new THREE.MeshStandardMaterial({ + color: "#FFD700", + roughness: 0.4, + metalness: 1, + }), +}; + +const sphere = new THREE.Mesh(geometry, materials.black); +scene.add(sphere); + +const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); +scene.add(ambientLight); + +const pointLight = new THREE.PointLight(0xffffff, 1); +pointLight.position.set(5, 5, 5); +scene.add(pointLight); + +const controls = new OrbitControls(camera, renderer.domElement); +controls.enableDamping = true; + +const buttons = document.querySelectorAll("button"); + +buttons.forEach((btn) => { + btn.addEventListener("click", () => { + const variant = btn.getAttribute("data-variant"); + + sphere.material = materials[variant]; + + buttons.forEach((b) => b.classList.remove("active")); + btn.classList.add("active"); + }); +}); + +function animate() { + requestAnimationFrame(animate); + + controls.update(); + + sphere.rotation.y += 0.01; + + renderer.render(scene, camera); +} +animate(); + +window.addEventListener("resize", () => { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); +}); \ No newline at end of file diff --git a/Week-3/Task-1/vanilla/package.json b/Week-3/Task-1/vanilla/package.json new file mode 100644 index 0000000..26abecc --- /dev/null +++ b/Week-3/Task-1/vanilla/package.json @@ -0,0 +1,18 @@ +{ + "name": "week3-task1-vanilla", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "vite": "^8.0.1" + }, + "dependencies": { + "three": "^0.183.2" + } +} diff --git a/Week-3/Task-1/vanilla/style.css b/Week-3/Task-1/vanilla/style.css new file mode 100644 index 0000000..e69de29 diff --git a/Week-3/Task-2/r3f/.gitignore b/Week-3/Task-2/r3f/.gitignore new file mode 100644 index 0000000..54f07af --- /dev/null +++ b/Week-3/Task-2/r3f/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? \ No newline at end of file diff --git a/Week-3/Task-2/r3f/README.md b/Week-3/Task-2/r3f/README.md new file mode 100644 index 0000000..57cb1aa --- /dev/null +++ b/Week-3/Task-2/r3f/README.md @@ -0,0 +1,10 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler \ No newline at end of file diff --git a/Week-3/Task-2/r3f/eslint.config.js b/Week-3/Task-2/r3f/eslint.config.js new file mode 100644 index 0000000..0cf397c --- /dev/null +++ b/Week-3/Task-2/r3f/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) \ No newline at end of file diff --git a/Week-3/Task-2/r3f/index.html b/Week-3/Task-2/r3f/index.html new file mode 100644 index 0000000..a1c874e --- /dev/null +++ b/Week-3/Task-2/r3f/index.html @@ -0,0 +1,13 @@ + + + + + + + r3f + + +
+ + + \ No newline at end of file diff --git a/Week-3/Task-2/r3f/package.json b/Week-3/Task-2/r3f/package.json new file mode 100644 index 0000000..1c50f01 --- /dev/null +++ b/Week-3/Task-2/r3f/package.json @@ -0,0 +1,31 @@ +{ + "name": "week3-task2-r3f", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@react-three/drei": "9.105.6", + "@react-three/fiber": "^9.5.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "three": "^0.183.2" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "@eslint/js": "^9.39.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } +} \ No newline at end of file diff --git a/Week-3/Task-2/r3f/src/App.css b/Week-3/Task-2/r3f/src/App.css new file mode 100644 index 0000000..659e4e5 --- /dev/null +++ b/Week-3/Task-2/r3f/src/App.css @@ -0,0 +1,41 @@ +.app-container { + width: 100vw; + height: 100vh; + position: relative; + background-color: white; + overflow: hidden; +} + +#controls { + position: absolute; + top: 20px; + left: 20px; + z-index: 10; + display: flex; + gap: 10px; +} + +button { + padding: 8px 16px; + cursor: pointer; + background: #f0f0f0; + border: 1px solid #ccc; + border-radius: 4px; + font-weight: 500; + transition: all 0.2s; +} + +button:hover { + background: #e0e0e0; +} + +button.active { + background: #333; + color: white; + border-color: #333; +} + +.canvas-wrapper { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/Week-3/Task-2/r3f/src/App.jsx b/Week-3/Task-2/r3f/src/App.jsx new file mode 100644 index 0000000..a6f9066 --- /dev/null +++ b/Week-3/Task-2/r3f/src/App.jsx @@ -0,0 +1,53 @@ +import React, { useState} from 'react'; +import { Canvas } from '@react-three/fiber'; +import { OrbitControls, PerspectiveCamera, useTexture } from '@react-three/drei'; +import './App.css'; + +const planetUrls = { + earth: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQZVsp7bSmsdGhM1GouOYgZ6l06Za__Z1ZY8A&s', + moon: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcROh1go667NHsMdzLyvI-0tt9Mn0eugRp0xhQ&s', + sun: 'https://upload.wikimedia.org/wikipedia/commons/a/a4/Solarsystemscope_texture_8k_sun.jpg', +}; + +function Planet({ variant }) { + const textures = useTexture(planetUrls); + + return ( + + + + + ); +} + +export default function App() { + const [activeVariant, setActiveVariant] = useState('earth'); + + return ( +
+
+ {Object.keys(planetUrls).map((variant) => ( + + ))} +
+ +
+ + + + + + + + + +
+
+ ); +} \ No newline at end of file diff --git a/Week-3/Task-2/r3f/src/index.css b/Week-3/Task-2/r3f/src/index.css new file mode 100644 index 0000000..7ee6713 --- /dev/null +++ b/Week-3/Task-2/r3f/src/index.css @@ -0,0 +1,12 @@ +* { + box-sizing: border-box; +} + +body, html, #root { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; + background-color: #111; +} \ No newline at end of file diff --git a/Week-3/Task-2/r3f/src/main.jsx b/Week-3/Task-2/r3f/src/main.jsx new file mode 100644 index 0000000..9347e15 --- /dev/null +++ b/Week-3/Task-2/r3f/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) \ No newline at end of file diff --git a/Week-3/Task-2/r3f/vite.config.js b/Week-3/Task-2/r3f/vite.config.js new file mode 100644 index 0000000..8d60bf7 --- /dev/null +++ b/Week-3/Task-2/r3f/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) \ No newline at end of file diff --git a/Week-3/Task-2/report.md b/Week-3/Task-2/report.md new file mode 100644 index 0000000..a094fce --- /dev/null +++ b/Week-3/Task-2/report.md @@ -0,0 +1 @@ +# Task 2 Report diff --git a/Week-3/Task-2/thob/notes.md b/Week-3/Task-2/thob/notes.md new file mode 100644 index 0000000..e4ad8b8 --- /dev/null +++ b/Week-3/Task-2/thob/notes.md @@ -0,0 +1,22 @@ +# Thob Builder Notes: Task 2 - Texture Switcher + +## Overview +Implemented a planetary texture switcher (Earth/Moon) using a `RadioGroup` for the UI and the built-in `MaterialVariant` system for texture swapping. + +## Visual Observations +- **Texture Resolution**: The builder handles texture mapping on a sphere smoothly. +- **UI Interaction**: Using a `RadioGroup` feels more natural for a configurator pattern compared to a single toggle button. + +## Technical Observations (Console Logs) +During development in the builder, several warnings and errors were observed: +- **404 Errors**: `GET https://builder.thob.studio/builder/... 404 (Not Found)`. +- **Method Registration**: `GetBindingData... method already registered`. This appears repeatedly in the logs during the preview phase. +- **Hydration Warnings**: `No HydrateFallback element provided to render during initial hydration`. +- **Component State**: `undefined is changing from uncontrolled to controlled`. This suggests a potential issue in how the builder manages internal component state when switching variants via `RadioGroup`. + +## Builder Workflow +- **Node Hierarchy**: The UI was structured using a `RadioGroup` -> `For` loop -> `RadioGroupItem` layout, demonstrating high-level UI component support in the builder. +- **State Linking**: Connecting the `RadioGroup` selection to the `MaterialVariant` property was straightforward in the properties panel. + +## Conclusion +The Thob Builder's `RadioGroup` component is a strong candidate for professional configurators. The process of linking textures to UI elements is intuitive and requires zero code. However, the runtime console warnings should be investigated to ensure production stability. diff --git a/Week-3/Task-2/vanilla/index.html b/Week-3/Task-2/vanilla/index.html new file mode 100644 index 0000000..cf4f562 --- /dev/null +++ b/Week-3/Task-2/vanilla/index.html @@ -0,0 +1,17 @@ + + + + + Task 2 — Texture / Surface Variant Switcher + + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/Week-3/Task-2/vanilla/main.js b/Week-3/Task-2/vanilla/main.js new file mode 100644 index 0000000..30c0687 --- /dev/null +++ b/Week-3/Task-2/vanilla/main.js @@ -0,0 +1,75 @@ +import * as THREE from "three"; +import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; + +const scene = new THREE.Scene(); +scene.background = new THREE.Color("white"); + +const camera = new THREE.PerspectiveCamera( + 75, + window.innerWidth / window.innerHeight, + 0.1, + 1000 +); +camera.position.z = 5; + +const renderer = new THREE.WebGLRenderer(); +renderer.setSize(window.innerWidth, window.innerHeight); +document.body.appendChild(renderer.domElement); + +const geometry = new THREE.SphereGeometry(1.5, 100, 100); + +const loader = new THREE.TextureLoader(); + +const textures = { + earth: loader.load('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQZVsp7bSmsdGhM1GouOYgZ6l06Za__Z1ZY8A&s'), + moon: loader.load('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcROh1go667NHsMdzLyvI-0tt9Mn0eugRp0xhQ&s'), + sun: loader.load('https://upload.wikimedia.org/wikipedia/commons/a/a4/Solarsystemscope_texture_8k_sun.jpg') +}; + +const material = new THREE.MeshStandardMaterial({ + map: textures.earth, + roughness: 0.6 +}); +const mesh = new THREE.Mesh(geometry, material); +scene.add(mesh); + +const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); +scene.add(ambientLight); + +const pointLight = new THREE.PointLight(0xffffff, 1); +pointLight.position.set(5, 5, 5); +scene.add(pointLight); + +const controls = new OrbitControls(camera, renderer.domElement); +controls.enableDamping = true; + +const buttons = document.querySelectorAll("button"); + +buttons.forEach((btn) => { + btn.addEventListener("click", () => { + const variant = btn.getAttribute("data-variant"); + + mesh.material.map = textures[variant]; + mesh.material.needsUpdate = true; + + buttons.forEach((b) => b.classList.remove("active")); + btn.classList.add("active"); + }); +}); + +function animate() { + requestAnimationFrame(animate); + + controls.update(); + + mesh.rotation.y += 0.01; + + renderer.render(scene, camera); +} +animate(); + +window.addEventListener("resize", () => { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); +}); diff --git a/Week-3/Task-2/vanilla/package.json b/Week-3/Task-2/vanilla/package.json new file mode 100644 index 0000000..1bfefa4 --- /dev/null +++ b/Week-3/Task-2/vanilla/package.json @@ -0,0 +1,18 @@ +{ + "name": "week3-task2-vanilla", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "vite": "^8.0.1" + }, + "dependencies": { + "three": "^0.183.2" + } +} diff --git a/Week-3/Task-3/r3f/.gitignore b/Week-3/Task-3/r3f/.gitignore new file mode 100644 index 0000000..54f07af --- /dev/null +++ b/Week-3/Task-3/r3f/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? \ No newline at end of file diff --git a/Week-3/Task-3/r3f/README.md b/Week-3/Task-3/r3f/README.md new file mode 100644 index 0000000..57cb1aa --- /dev/null +++ b/Week-3/Task-3/r3f/README.md @@ -0,0 +1,10 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler \ No newline at end of file diff --git a/Week-3/Task-3/r3f/eslint.config.js b/Week-3/Task-3/r3f/eslint.config.js new file mode 100644 index 0000000..0cf397c --- /dev/null +++ b/Week-3/Task-3/r3f/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) \ No newline at end of file diff --git a/Week-3/Task-3/r3f/index.html b/Week-3/Task-3/r3f/index.html new file mode 100644 index 0000000..a1c874e --- /dev/null +++ b/Week-3/Task-3/r3f/index.html @@ -0,0 +1,13 @@ + + + + + + + r3f + + +
+ + + \ No newline at end of file diff --git a/Week-3/Task-3/r3f/package.json b/Week-3/Task-3/r3f/package.json new file mode 100644 index 0000000..dea72a1 --- /dev/null +++ b/Week-3/Task-3/r3f/package.json @@ -0,0 +1,31 @@ +{ + "name": "week3-task3-r3f", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@react-three/drei": "9.105.6", + "@react-three/fiber": "^9.5.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "three": "^0.183.2" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "@eslint/js": "^9.39.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } +} \ No newline at end of file diff --git a/Week-3/Task-3/r3f/src/App.css b/Week-3/Task-3/r3f/src/App.css new file mode 100644 index 0000000..dc48fc7 --- /dev/null +++ b/Week-3/Task-3/r3f/src/App.css @@ -0,0 +1,12 @@ +.app-container { + width: 100vw; + height: 100vh; + position: relative; + background-color: white; + overflow: hidden; +} + +.canvas-wrapper { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/Week-3/Task-3/r3f/src/App.jsx b/Week-3/Task-3/r3f/src/App.jsx new file mode 100644 index 0000000..893cc1e --- /dev/null +++ b/Week-3/Task-3/r3f/src/App.jsx @@ -0,0 +1,64 @@ +import React, { useState } from 'react'; +import { Canvas } from '@react-three/fiber'; +import { OrbitControls, PerspectiveCamera } from '@react-three/drei'; +import './App.css'; + +const variants = { + black: { + geometry: , + material: { color: "black", roughness: 1, metalness: 0 } + }, + silver: { + geometry: , + material: { color: "#C0C0C0", roughness: 0.3, metalness: 1 } + }, + gold: { + geometry: , + material: { color: "#FFD700", roughness: 0.4, metalness: 1 } + } +}; + +function Product({ variant }) { + const { geometry, material } = variants[variant]; + + return ( + + {geometry} + + + ); +} + +export default function App() { + const [activeVariant, setActiveVariant] = useState('black'); + + return ( +
+
+ {Object.keys(variants).map((variant) => ( + + ))} +
+ +
+ + + + + + + + + + + +
+
+ ); +} \ No newline at end of file diff --git a/Week-3/Task-3/r3f/src/index.css b/Week-3/Task-3/r3f/src/index.css new file mode 100644 index 0000000..7ee6713 --- /dev/null +++ b/Week-3/Task-3/r3f/src/index.css @@ -0,0 +1,12 @@ +* { + box-sizing: border-box; +} + +body, html, #root { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; + background-color: #111; +} \ No newline at end of file diff --git a/Week-3/Task-3/r3f/src/main.jsx b/Week-3/Task-3/r3f/src/main.jsx new file mode 100644 index 0000000..9347e15 --- /dev/null +++ b/Week-3/Task-3/r3f/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) \ No newline at end of file diff --git a/Week-3/Task-3/r3f/vite.config.js b/Week-3/Task-3/r3f/vite.config.js new file mode 100644 index 0000000..8d60bf7 --- /dev/null +++ b/Week-3/Task-3/r3f/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) \ No newline at end of file diff --git a/Week-3/Task-3/report.md b/Week-3/Task-3/report.md new file mode 100644 index 0000000..e42388a --- /dev/null +++ b/Week-3/Task-3/report.md @@ -0,0 +1 @@ +# Task 3 Report diff --git a/Week-3/Task-3/thob/notes.md b/Week-3/Task-3/thob/notes.md new file mode 100644 index 0000000..e69de29 diff --git a/Week-3/Task-3/vanilla/index.html b/Week-3/Task-3/vanilla/index.html new file mode 100644 index 0000000..e2d9ea7 --- /dev/null +++ b/Week-3/Task-3/vanilla/index.html @@ -0,0 +1,18 @@ + + + + + Task 3 — UI-Controlled Product Option + + + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/Week-3/Task-3/vanilla/main.js b/Week-3/Task-3/vanilla/main.js new file mode 100644 index 0000000..170bb3f --- /dev/null +++ b/Week-3/Task-3/vanilla/main.js @@ -0,0 +1,92 @@ +import * as THREE from "three"; +import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; + +const scene = new THREE.Scene(); +scene.background = new THREE.Color("white"); + +const camera = new THREE.PerspectiveCamera( + 75, + window.innerWidth / window.innerHeight, + 0.1, + 1000 +); +camera.position.z = 5; + +const renderer = new THREE.WebGLRenderer(); +renderer.setSize(window.innerWidth, window.innerHeight); +document.body.appendChild(renderer.domElement); + +const geometries = { + black: new THREE.BoxGeometry(2, 2, 2), + silver: new THREE.SphereGeometry(1.5, 32, 32), + gold: new THREE.TorusGeometry(1.2, 0.4, 16, 100), +}; + +const materials = { + black: new THREE.MeshStandardMaterial({ + color: "black", + roughness: 1, + metalness: 0, + }), + silver: new THREE.MeshStandardMaterial({ + color: "#C0C0C0", + roughness: 0.3, + metalness: 1, + }), + gold: new THREE.MeshStandardMaterial({ + color: "#FFD700", + roughness: 0.4, + metalness: 1, + }), +}; + +let currentVariant = "black"; + +let mesh = new THREE.Mesh( + geometries[currentVariant], + materials[currentVariant] +); +scene.add(mesh); + +scene.add(new THREE.AmbientLight(0xffffff, 0.6)); + +const pointLight = new THREE.PointLight(0xffffff, 1); +pointLight.position.set(5, 5, 5); +scene.add(pointLight); + +const controls = new OrbitControls(camera, renderer.domElement); +controls.enableDamping = true; + +function updateScene() { + mesh.geometry = geometries[currentVariant]; + mesh.material = materials[currentVariant]; +} + +const buttons = document.querySelectorAll("button"); + +buttons.forEach((btn) => { + btn.addEventListener("click", () => { + const variant = btn.getAttribute("data-variant"); + + currentVariant = variant; + updateScene(); + + buttons.forEach((b) => b.classList.remove("active")); + btn.classList.add("active"); + }); +}); + +function animate() { + requestAnimationFrame(animate); + + controls.update(); + + renderer.render(scene, camera); +} +animate(); + +window.addEventListener("resize", () => { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); +}); \ No newline at end of file diff --git a/Week-3/Task-3/vanilla/package.json b/Week-3/Task-3/vanilla/package.json new file mode 100644 index 0000000..9c0bac1 --- /dev/null +++ b/Week-3/Task-3/vanilla/package.json @@ -0,0 +1,18 @@ +{ + "name": "week3-task3-vanilla", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "vite": "^8.0.1" + }, + "dependencies": { + "three": "^0.183.2" + } +} diff --git a/Week-3/Task-4/r3f/.gitignore b/Week-3/Task-4/r3f/.gitignore new file mode 100644 index 0000000..54f07af --- /dev/null +++ b/Week-3/Task-4/r3f/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? \ No newline at end of file diff --git a/Week-3/Task-4/r3f/README.md b/Week-3/Task-4/r3f/README.md new file mode 100644 index 0000000..57cb1aa --- /dev/null +++ b/Week-3/Task-4/r3f/README.md @@ -0,0 +1,10 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler \ No newline at end of file diff --git a/Week-3/Task-4/r3f/eslint.config.js b/Week-3/Task-4/r3f/eslint.config.js new file mode 100644 index 0000000..0cf397c --- /dev/null +++ b/Week-3/Task-4/r3f/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) \ No newline at end of file diff --git a/Week-3/Task-4/r3f/index.html b/Week-3/Task-4/r3f/index.html new file mode 100644 index 0000000..a1c874e --- /dev/null +++ b/Week-3/Task-4/r3f/index.html @@ -0,0 +1,13 @@ + + + + + + + r3f + + +
+ + + \ No newline at end of file diff --git a/Week-3/Task-4/r3f/package.json b/Week-3/Task-4/r3f/package.json new file mode 100644 index 0000000..32abd93 --- /dev/null +++ b/Week-3/Task-4/r3f/package.json @@ -0,0 +1,31 @@ +{ + "name": "week3-task4-r3f", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@react-three/drei": "9.105.6", + "@react-three/fiber": "^9.5.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "three": "^0.183.2" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "@eslint/js": "^9.39.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } +} \ No newline at end of file diff --git a/Week-3/Task-4/r3f/src/App.css b/Week-3/Task-4/r3f/src/App.css new file mode 100644 index 0000000..dc48fc7 --- /dev/null +++ b/Week-3/Task-4/r3f/src/App.css @@ -0,0 +1,12 @@ +.app-container { + width: 100vw; + height: 100vh; + position: relative; + background-color: white; + overflow: hidden; +} + +.canvas-wrapper { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/Week-3/Task-4/r3f/src/App.jsx b/Week-3/Task-4/r3f/src/App.jsx new file mode 100644 index 0000000..7e37115 --- /dev/null +++ b/Week-3/Task-4/r3f/src/App.jsx @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +import { Canvas } from '@react-three/fiber'; +import { OrbitControls, PerspectiveCamera } from '@react-three/drei'; +import './App.css'; + +function InteractiveObject() { + const [selected, setSelected] = useState(false); + + return ( + setSelected(!selected)} + scale={selected ? 1.2 : 1} + rotation={[0, 0, 0]} + > + + + + ); +} + +export default function App() { + return ( +
+
+

Interaction Pattern — Click on the object

+
+ +
+ + + + + + + + + + + +
+
+ ); +} \ No newline at end of file diff --git a/Week-3/Task-4/r3f/src/index.css b/Week-3/Task-4/r3f/src/index.css new file mode 100644 index 0000000..7ee6713 --- /dev/null +++ b/Week-3/Task-4/r3f/src/index.css @@ -0,0 +1,12 @@ +* { + box-sizing: border-box; +} + +body, html, #root { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; + background-color: #111; +} \ No newline at end of file diff --git a/Week-3/Task-4/r3f/src/main.jsx b/Week-3/Task-4/r3f/src/main.jsx new file mode 100644 index 0000000..9347e15 --- /dev/null +++ b/Week-3/Task-4/r3f/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) \ No newline at end of file diff --git a/Week-3/Task-4/r3f/vite.config.js b/Week-3/Task-4/r3f/vite.config.js new file mode 100644 index 0000000..8d60bf7 --- /dev/null +++ b/Week-3/Task-4/r3f/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) \ No newline at end of file diff --git a/Week-3/Task-4/report.md b/Week-3/Task-4/report.md new file mode 100644 index 0000000..e6e75ff --- /dev/null +++ b/Week-3/Task-4/report.md @@ -0,0 +1 @@ +# Task 4 Report diff --git a/Week-3/Task-4/thob/notes.md b/Week-3/Task-4/thob/notes.md new file mode 100644 index 0000000..e69de29 diff --git a/Week-3/Task-4/vanilla/index.html b/Week-3/Task-4/vanilla/index.html new file mode 100644 index 0000000..9f0b5a6 --- /dev/null +++ b/Week-3/Task-4/vanilla/index.html @@ -0,0 +1,14 @@ + + + + + Task 4 — Click To Highlight / Select + + + +

Interaction Pattern- click on the object

+ + + \ No newline at end of file diff --git a/Week-3/Task-4/vanilla/main.js b/Week-3/Task-4/vanilla/main.js new file mode 100644 index 0000000..30c4b97 --- /dev/null +++ b/Week-3/Task-4/vanilla/main.js @@ -0,0 +1,70 @@ +import * as THREE from "three"; +import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; + +const scene = new THREE.Scene(); +scene.background = new THREE.Color("white"); + +const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); +camera.position.z = 5; + +const renderer = new THREE.WebGLRenderer({ antialias: true }); +renderer.setSize(window.innerWidth, window.innerHeight); +document.body.appendChild(renderer.domElement); + +const geometry = new THREE.TorusKnotGeometry(1, 0.4, 100, 16); +const material = new THREE.MeshStandardMaterial({ color: "#ccc", roughness: 0.5 }); +const mesh = new THREE.Mesh(geometry, material); +scene.add(mesh); + +scene.add(new THREE.AmbientLight(0xffffff, 0.6)); +const pointLight = new THREE.PointLight(0xffffff, 1); +pointLight.position.set(5, 5, 5); +scene.add(pointLight); + +const controls = new OrbitControls(camera, renderer.domElement); +controls.enableDamping = true; + +const raycaster = new THREE.Raycaster(); +const mouse = new THREE.Vector2(); +let isSelected = false; + +window.addEventListener("click", (event) => { + mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; + + raycaster.setFromCamera(mouse, camera); + const intersects = raycaster.intersectObject(mesh); + + if (intersects.length > 0) { + isSelected = !isSelected; + updateAppearance(); + } +}); + +function updateAppearance() { + if (isSelected) { + mesh.scale.set(1.2, 1.2, 1.2); + mesh.material.color.set("#3498db"); + mesh.material.emissive.set("#1e3799"); + mesh.material.emissiveIntensity = 0.5; + } else { + mesh.scale.set(1, 1, 1); + mesh.material.color.set("#ccc"); + mesh.material.emissive.set("#000"); + mesh.material.emissiveIntensity = 0; + } +} + +function animate() { + requestAnimationFrame(animate); + controls.update(); + mesh.rotation.y += 0.01; + renderer.render(scene, camera); +} +animate(); + +window.addEventListener("resize", () => { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); +}); diff --git a/Week-3/Task-4/vanilla/package.json b/Week-3/Task-4/vanilla/package.json new file mode 100644 index 0000000..af089e8 --- /dev/null +++ b/Week-3/Task-4/vanilla/package.json @@ -0,0 +1,18 @@ +{ + "name": "week3-task4-vanilla", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "packageManager": "yarn@1.22.22", + "devDependencies": { + "vite": "^8.0.1" + }, + "dependencies": { + "three": "^0.183.2" + } +} \ No newline at end of file diff --git a/Week-3/Week-3-PersonalSummary.md b/Week-3/Week-3-PersonalSummary.md new file mode 100644 index 0000000..7fc539f --- /dev/null +++ b/Week-3/Week-3-PersonalSummary.md @@ -0,0 +1 @@ +# Week 3 Personal Summary diff --git a/package.json b/package.json index 25be8f2..5e68fe3 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "packageManager": "yarn@1.22.22", "workspaces": [ "Week-1/**", - "Week-2/**" + "Week-2/**", + "Week-3/**" ], "dependencies": { "@react-three/fiber": "^9.5.0",