commit 2c0eb2fcc39ac8a062028193b79f6c4d91fae944 Author: Antigravity Date: Thu Jul 16 14:03:58 2026 +0530 Initial commit of template diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8990dad --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Dependencies +node_modules + +# Lockfiles +bun.lock + +# Vite +.vite + +# Build output +dist + +# Cache +cache + +# OS files +.DS_Store diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..4fa125d --- /dev/null +++ b/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_]' }], + }, + }, +]) diff --git a/index.html b/index.html new file mode 100644 index 0000000..cf1c48a --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + Three.js Game + + +
+ + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..3f8d532 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "noah-threejs-template", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview", + "watch": "vite build --watch" + }, + "dependencies": { + "@supabase/supabase-js": "2.57.4", + "react": "19.1.0", + "react-dom": "19.1.0", + "three": "0.160.0" + }, + "devDependencies": { + "@eslint/js": "9.9.1", + "@types/react": "19.0.0", + "@types/react-dom": "19.0.0", + "@vitejs/plugin-react-swc": "4.3.0", + "eslint": "9.9.1", + "eslint-plugin-react-hooks": "5.1.0-rc.0", + "eslint-plugin-react-refresh": "0.4.11", + "globals": "15.9.0", + "vite": "8.0.8" + } +} diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..cf7ed4a --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,18 @@ +import { useEffect, useRef } from "react"; +import { ThreeScene } from "./game/ThreeScene"; + +function App() { + const containerRef = useRef(null); + const sceneRef = useRef(null); + + useEffect(() => { + if (containerRef.current && !sceneRef.current) { + sceneRef.current = new ThreeScene(containerRef.current); + sceneRef.current.init(); + } + }, []); + + return
; +} + +export default App; diff --git a/src/game/ThreeScene.js b/src/game/ThreeScene.js new file mode 100644 index 0000000..4d00a44 --- /dev/null +++ b/src/game/ThreeScene.js @@ -0,0 +1,171 @@ +import * as THREE from "three"; +import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; + +export class ThreeScene { + constructor(container) { + this.container = container; + this.scene = new THREE.Scene(); + this.camera = new THREE.PerspectiveCamera( + 75, + this.container.clientWidth / this.container.clientHeight, + 0.1, + 1000 + ); + this.renderer = new THREE.WebGLRenderer({ antialias: true }); + this.controls = null; + this.clock = new THREE.Clock(); + + this.playerObject = null; + this.planetObject = null; + } + + init() { + this.renderer.setSize( + this.container.clientWidth, + this.container.clientHeight + ); + this.renderer.setPixelRatio(window.devicePixelRatio); + this.renderer.setClearColor(0x101020); + this.container.appendChild(this.renderer.domElement); + + this.camera.position.set(0, 10, 20); + + const ambientLight = new THREE.AmbientLight(0x404040); + this.scene.add(ambientLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); + directionalLight.position.set(10, 15, 10); + this.scene.add(directionalLight); + + this.addStars(); + + this.createPlanet(); + this.createPlayer(); + + this.controls = new OrbitControls(this.camera, this.renderer.domElement); + this.controls.enableDamping = true; + this.controls.dampingFactor = 0.05; + this.controls.screenSpacePanning = false; + this.controls.minDistance = 5; + this.controls.maxDistance = 100; + this.controls.target.set(0, 0, 0); + + window.addEventListener("resize", () => this.onWindowResize()); + + this.animate(); + } + + addStars() { + const starsGeometry = new THREE.BufferGeometry(); + const starsMaterial = new THREE.PointsMaterial({ + color: 0xffffff, + size: 0.05, + sizeAttenuation: true, + }); + + const starsVertices = []; + for (let i = 0; i < 10000; i++) { + const x = THREE.MathUtils.randFloatSpread(200); + const y = THREE.MathUtils.randFloatSpread(200); + const z = THREE.MathUtils.randFloatSpread(200); + if (Math.sqrt(x * x + y * y + z * z) > 20) { + starsVertices.push(x, y, z); + } else { + i--; + } + } + + starsGeometry.setAttribute( + "position", + new THREE.Float32BufferAttribute(starsVertices, 3) + ); + const stars = new THREE.Points(starsGeometry, starsMaterial); + this.scene.add(stars); + } + + createPlanet() { + const planetGeometry = new THREE.SphereGeometry(4, 32, 32); + const planetMaterial = new THREE.MeshPhongMaterial({ + color: 0x4a6f8a, + shininess: 10, + }); + this.planetObject = new THREE.Mesh(planetGeometry, planetMaterial); + this.scene.add(this.planetObject); + } + + createPlayer() { + const playerGroup = new THREE.Group(); + + const bodyGeometry = new THREE.ConeGeometry(0.8, 2, 8); + const bodyMaterial = new THREE.MeshPhongMaterial({ + color: 0xe88a5b, + shininess: 30, + }); + const playerBody = new THREE.Mesh(bodyGeometry, bodyMaterial); + playerBody.rotation.x = Math.PI / 2; + playerGroup.add(playerBody); + + const cockpitGeometry = new THREE.SphereGeometry( + 0.4, + 16, + 16, + 0, + Math.PI * 2, + 0, + Math.PI / 2 + ); + const cockpitMaterial = new THREE.MeshPhongMaterial({ + color: 0xadd8e6, + transparent: true, + opacity: 0.6, + shininess: 50, + }); + const cockpit = new THREE.Mesh(cockpitGeometry, cockpitMaterial); + cockpit.rotation.x = Math.PI; + cockpit.position.set(0, 0, -0.6); + playerBody.add(cockpit); + + this.playerObject = playerGroup; + this.playerObject.position.set(0, 0, 10); + this.scene.add(this.playerObject); + } + + onWindowResize() { + this.camera.aspect = + this.container.clientWidth / this.container.clientHeight; + this.camera.updateProjectionMatrix(); + this.renderer.setSize( + this.container.clientWidth, + this.container.clientHeight + ); + this.renderer.setPixelRatio(window.devicePixelRatio); + } + + animate() { + requestAnimationFrame(() => this.animate()); + + const delta = this.clock.getDelta(); + const elapsedTime = this.clock.getElapsedTime(); + + if (this.planetObject) { + this.planetObject.rotation.y += 0.2 * delta; + } + + if (this.playerObject) { + const orbitRadius = 10; + const orbitSpeed = 0.5; + this.playerObject.position.x = + Math.cos(elapsedTime * orbitSpeed) * orbitRadius; + this.playerObject.position.z = + Math.sin(elapsedTime * orbitSpeed) * orbitRadius; + this.playerObject.lookAt(this.planetObject.position); + this.playerObject.rotateY(Math.PI); + } + + if (this.controls) { + this.controls.update(); + } + + this.renderer.render(this.scene, this.camera); + } +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..ec00aa9 --- /dev/null +++ b/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + overflow: hidden; + background-color: #000; +} + +#game-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/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( + + + , +) diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..38677b3 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,21 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; + +export default defineConfig(({ mode }) => ({ + base: "/games/", + server: { + host: "0.0.0.0", + port: 3000, + allowedHosts: true, + hmr: { + overlay: false, + timeout: 15000, + }, + watch: { + usePolling: true, + interval: 500, + binaryInterval: 500, + }, + }, + plugins: [react()], +}));