├── .gitignore ├── README.md ├── declarations.d.ts ├── package.json ├── src ├── index.html ├── script.ts ├── shaders │ ├── fragment.glsl │ └── vertex.glsl └── style.css ├── static └── boilerplate.gif ├── tsconfig.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Basic Three.js Template 2 | 3 | ## Now supports TypeScript as well 4 | 5 | A streamlined boilerplate for Three.js projects, designed to get you up and running quickly. 6 | 7 | ![Boilerplate demo](./static/boilerplate.gif) 8 | 9 | ## 🚀 Quick Start 10 | 11 | Follow these steps to set up your project using this boilerplate: 12 | 13 | ```bash 14 | # Clone the repository and cd into the project 15 | git clone https://github.com/zoyron/threejs-boilerplate.git your-project-name 16 | cd your-project-name 17 | 18 | # Remove git history and start fresh with your own Git history 19 | rm -rf .git 20 | git init 21 | 22 | # Install dependencies 23 | npm install 24 | 25 | # Run the development server 26 | npm run dev 27 | ``` 28 | 29 | Your project is now running at http://localhost:5173 (or another port if 5173 is occupied). 30 | 31 | ## Threejs Project Structure 32 | 33 | ### Base Setup(includes the following): 34 | 35 | - Canvas 36 | - Scene 37 | - Sizes(the object) 38 | 39 | ### The Camera, groups(optional) and lights(optional): 40 | 41 | - Perspective Camera(most usualy and popular choice) 42 | - Lights(optional, with ambient light being the most popular choice) 43 | 44 | ### Creating an object and adding it to scene 45 | 46 | - Creating geometry or points-geometry; could be inbuilt, custom, random or using shaders 47 | - Creating material or points-material; could be inbuilt, custom, random or using shaders 48 | - Creating mesh or points; could be inbuilt, custom, random or using shaders 49 | 50 | > above three are the points where we mostly use shaders 51 | 52 | - Adding the created mesh or points to the scene or group 53 | 54 | ### Renderer and Resizing 55 | 56 | - Adding a scene renderer 57 | - Adding a window resizing event listener, and updating the render inside it 58 | 59 | ### Controls and Animate function 60 | 61 | - Adding orbit controls and damping them if required 62 | - adding the animate() function, and giving necessary logic and functionality to it 63 | - calling the animate() function 64 | -------------------------------------------------------------------------------- /declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.glsl" { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "threejs-template", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^5.5.3", 13 | "vite": "^6.2.0", 14 | "vite-plugin-glsl": "^1.3.0", 15 | "vite-plugin-restart": "^0.4.1" 16 | }, 17 | "dependencies": { 18 | "@types/three": "^0.169.0", 19 | "lil-gui": "^0.20.0", 20 | "three": "^0.174.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Threejs Template 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/script.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from "three"; 2 | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; 3 | 4 | /** 5 | * Base setup 6 | */ 7 | 8 | // Canvas 9 | const canvas = document.querySelector("canvas.webgl"); 10 | 11 | // Scene 12 | const scene = new THREE.Scene(); 13 | scene.background = new THREE.Color(0xf0f0f0); 14 | 15 | // Sizes 16 | const sizes = { 17 | width: window.innerWidth, 18 | height: window.innerHeight, 19 | }; 20 | 21 | /** 22 | * Camera and lights(optional) 23 | */ 24 | 25 | // Perspective Camera 26 | const camera = new THREE.PerspectiveCamera( 27 | 75, 28 | sizes.width / sizes.height, 29 | 0.1, 30 | 1000 31 | ); 32 | camera.position.set(3, 3, 3); 33 | scene.add(camera); 34 | 35 | /** 36 | * Adding a base mesh 37 | */ 38 | const side = 1; 39 | const geometry = new THREE.BoxGeometry(side,side,side, 8, 8, 8); 40 | const material = new THREE.MeshNormalMaterial(); 41 | const mesh = new THREE.Mesh(geometry, material); 42 | scene.add(mesh); 43 | 44 | /** 45 | * Renderer and Resizing 46 | */ 47 | // renderer 48 | const renderer = new THREE.WebGLRenderer({ 49 | canvas: canvas, 50 | }); 51 | renderer.setSize(sizes.width, sizes.height); 52 | renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); 53 | 54 | // Resizing 55 | window.addEventListener("resize", () => { 56 | // Update sizes 57 | sizes.width = window.innerWidth; 58 | sizes.height = window.innerHeight; 59 | 60 | // Update camera 61 | camera.aspect = sizes.width / sizes.height; 62 | camera.updateProjectionMatrix(); 63 | 64 | // Update renderer 65 | renderer.setSize(sizes.width, sizes.height); 66 | renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); 67 | }); 68 | 69 | /** 70 | * Animate and controls 71 | */ 72 | // Controls 73 | const controls = new OrbitControls(camera, canvas); 74 | controls.enableDamping = true; 75 | 76 | // Animate 77 | const animate = () => { 78 | // Rotate mesh 79 | mesh.rotation.x += 0.0125; 80 | mesh.rotation.y += 0.0125; 81 | 82 | // Update controls 83 | controls.update(); 84 | 85 | // Adding renderer 86 | renderer.render(scene, camera); 87 | 88 | // Call animate again on the next frame 89 | window.requestAnimationFrame(animate); 90 | }; 91 | 92 | animate(); 93 | -------------------------------------------------------------------------------- /src/shaders/fragment.glsl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoyron/threejs-template/dd312257598e33ae019ba1d326bd23ebf96d7be0/src/shaders/fragment.glsl -------------------------------------------------------------------------------- /src/shaders/vertex.glsl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoyron/threejs-template/dd312257598e33ae019ba1d326bd23ebf96d7be0/src/shaders/vertex.glsl -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | body, 2 | html { 3 | margin: 0; 4 | padding: 0; 5 | width: 100%; 6 | height: 100vh; 7 | overflow: hidden; 8 | background-color: black; 9 | } 10 | 11 | canvas { 12 | display: block; 13 | position: fixed; 14 | top: 0; 15 | left: 0; 16 | width: 100%; 17 | height: 100%; 18 | } 19 | -------------------------------------------------------------------------------- /static/boilerplate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoyron/threejs-template/dd312257598e33ae019ba1d326bd23ebf96d7be0/static/boilerplate.gif -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "include": ["src/**/*.ts", "declarations.d.ts"] 23 | } 24 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import restart from 'vite-plugin-restart' 2 | import glsl from 'vite-plugin-glsl' 3 | 4 | export default { 5 | root: 'src/', 6 | publicDir: '../static/', 7 | base: './', 8 | server: 9 | { 10 | host: true, // Open to local network and display URL 11 | open: !('SANDBOX_URL' in process.env || 'CODESANDBOX_HOST' in process.env) // Open if it's not a CodeSandbox 12 | }, 13 | build: 14 | { 15 | outDir: '../dist', // Output in the dist/ folder 16 | emptyOutDir: true, // Empty the folder first 17 | sourcemap: true // Add sourcemap 18 | }, 19 | plugins: 20 | [ 21 | restart({ restart: [ '../static/**', ] }), // Restart server on static file change 22 | glsl() // Handle shader files 23 | ] 24 | } 25 | --------------------------------------------------------------------------------